October 17, 2015 21:29
Update
Laravel now comes with a Relationship morphMap
which takes care of this all in one place. Simply add this to your AppServiceProvider
use Illuminate\Database\Eloquent\Relations\Relation;
public function boot()
{
Relation::morphMap([
'album' => Album::class,
'photo' => Photo::class,
'user' => User::class,
]);
}
You can now use album
, photo
, etc. in your ENUM
s instead of the full class name.
Original Post
Let's say you have a Comment
class that has a morphTo
relationship with many other models. However, you don't want to store the full class name of the relationship in your database because that's a waste of space, and namespaces might change.
First, every model that has comments should define the morphClass
variable. This is just a shortened version of the class name.
class Album {
protected $morphClass = 'album';
}
class Photo {
protected $morphClass = 'photo';
}
Next, the Comment class should define an $entity_types
array which is basically the inverse of what you just did. It maps the short name to the full class name.
class Comment {
protected $entity_types = [
'album' => \App\Album::class,
'photo' => \App\Photo::class,
];
}
Finally, the Comment class should have an accessor for the entity_type
column. This takes the database value ("photo", "album", etc.) and converts it to the full class name ("\App\Photo", "\App\Album", etc.)
/**
* @param string $type short name
* @return string full class name
*/
public function getEntityTypeAttribute($type)
{
if ($type === null) {
return null;
}
$type = strtolower($type);
return array_get($this->entity_types, $type, $type);
}
Ideally, this should be either on your base model, or on a trait. That way the method can be reused on any class that has a morphTo relationship.