parapark
parapark

Reputation: 35

Laravel 4 querying relational relation

I've created 4 database tables:

Tool
ID | NAME | TOOLTYPE_ID

Tooltype
ID | NAME

Toolcategory
ID | NAME

Tool_Toolcategory
TOOL_ID | TOOLCATEGORY_ID

The models are as following:

class Tool extends Eloquent  {

 public function toolCategories()
 {
    return $this->belongsToMany('ToolCategory', 'tool_toolcategory', 'tool_id', 'toolcategory_id');
 }

 public function tooltype()
 {
    return $this->belongsTo('ToolType');
 }   
}

class ToolType extends Eloquent {

 public function tools()
 {
    return $this->hasMany('Tool', 'tooltype_id');
 }
}

class ToolCategory extends Eloquent {
 public function tools()
 {
    return $this->belongsToMany('Tool', 'tool_toolcategory', 'tool_id', 'toolcategory_id');
 }   
}

Ok, my problem is getting toolcategories based on created tools with a specific tooltype.
Example I want all the categories related to the tools that has the type "Software".
I am kinda lost, i have looked at trying to use scope in my toolcategory model, doing something like this:

public function scopeHasType($query, $type)
{
  return $query->whereHas('tools.tooltype', function($q) use ($type) 
  {
    $q->where('name', '=', $type);
  })->exists();
}


which didn't really work :) then i tried this

$categories = ToolCategory::whereHas('tools.tooltype', function($query)
{
  $query->where('tooltype_id', '=', 'Software');                
})->get();


again no luck. So i was hoping that this makes sense to someone, and they could push me in the right direction. Thank you in advance.

Upvotes: 1

Views: 444

Answers (1)

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81157

Eloquent naming convention says:

  1. ModelNames are StudlyCased & singular
  2. modelMethods are camelCased (relation dynamic properties need this)
  3. table_names are snake_cased & plural
  4. table_columns are snake_cased
  5. pivot_table is model1_model2 snake_cased singular (in alphabetical order)

That being said, Eloquent for a model ToolCategory looks for the table tool_categories.

So you need to specify table names whenever are not convention compliant (singular, not snake cased and so on):

// for example Tool model
protected $table = 'tool'; 

Also you need foreign keys to be passed to the relationship definition in order to let Eloquent know what to look for. However that you already did:

// ToolType model
public function tools()
{
    // here Eloquent would look for tool_type_id (based on related model)
    return $this->hasMany('Tool', 'tooltype_id');
}

// Tool model
public function tooltype()
{
    // here Eloquent looks for tooltype_id by default (based on relation name)
    return $this->belongsTo('ToolType');
}  

Now, your relations are OK with 1 exception (keys wrong order):

class ToolCategory extends Eloquent {
 public function tools()
 {
    return $this->belongsToMany('Tool', 'tool_toolcategory', 'toolcategory_id', 'tool_id');
 }

Finally, whereHas doesn't work on nested relation (yet, check this: https://github.com/laravel/framework/pull/4954), so at the moment you need this:

// ToolCategory model
public function scopeHasType($query, $type) 
{
  return $query->whereHas('tools', function ($q) use ($type) {
    $q->whereHas('tooltype', function($q) use ($type) {
      // use table prefix, since this is going to be join
      $q->where('tooltype.name', '=', $type);
    });
  });
}

Upvotes: 2

Related Questions