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 ENUMs 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.

Laravel, PHP