Reputation: 12708
Using Laravel 5.1, I'm trying to create a dynamic table where I can associate multiple item types with a module
. I went with a Polymorphic table and set the morphable_ids
and morphable_types
per module as such:
id module_id morphable_id morphable_type
1 1 1 App/Enemy
2 2 2 App/Enemy
3 3 1 App/Item
I get my modules through associated tasks
, aka modules
are eager loaded in with tasks. When I drill down into my task from the API call, and check module_items
, it shows the literal morphable_id
/morphable_type
rather than the App\Enemy
or App\Item
instances I was looking for:
more task obj properties...
"module":{
"id" : 1
"module_items":[
{
"id": 3,
"module_id": "3",
"morphable_id": "1",
"morphable_type": "App/Item"
}
]
}
So my question is, how can I actually retrieve the polymorphic model instance (like, I retrieve App\Item
of id 1
for module 1
)?
Here is some more information:
Models:
Task: loads with modules
class Task extends Model
{
protected $with = ['module'];
public function module()
{
return $this->belongsTo(Module::class);
}
}
Module
class Module extends Model
{
protected $with = ['module_items'];
public function task()
{
return $this->belongsTo(Task::class);
}
public function module_items()
{
return $this->hasMany(ModuleItem::class);
}
}
Polymorphic ModuleItem
model
class ModuleItem extends Model
{
public function typeable()
{
return $this->morphTo();
}
public function module()
{
return $this->belongsTo(Module::class);
}
}
Polymorphic relation on Item
class Item extends Model
{
public function module_item_types()
{
return $this->morphMany('App\ModuleItem', 'typeable');
}
}
Polymorphic relation on Enemy
class Enemy extends Model
{
public function module_item_types()
{
return $this->morphMany('App\ModuleItem', 'typeable');
}
}
Upvotes: 0
Views: 2322
Reputation: 112
Take a look at Illuminate\Database\Eloquent@morphMany
:
/**
* Define a polymorphic one-to-many relationship.
*
* @param string $related
* @param string $name
* @param string $type
* @param string $id
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
$instance = new $related;
// Here we will gather up the morph type and ID for the relationship so that we
// can properly query the intermediate table of a relation. Finally, we will
// get the table and create the relationship instances for the developers.
list($type, $id) = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphMany($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey);
}
If you follow the rabbit hole down through Illuminate\Database\Eloquent@getMorphs
you'll see that the DB table names are inferred through the $name
param if $type
is null. Your column names are being inferred as typeable_id
and typeable_type
instead of morphable_id
and morphable_type
.
Once that's fixed, you should be able to access the ModuleItem
's type like $module_item->typeable
(or whatever you rename the relationship to). If you wanted to eager load the type instance you would update ModuleItem
:
class ModuleItem extends Model
{
protected $with = ['typeable'];
public function typeable()
{
return $this->morphTo();
}
public function module()
{
return $this->belongsTo(Module::class);
}
}
Upvotes: 1