Laravel: Returning the namespaced owner of a polymorphic relation
I like @JarekTkaczyks solution and I would suggest you use that one. But, for the sake of completeness, there's is another way Taylor briefly mentions on github
You can add a attribute accessor for the imageable_type
attribute and then use a "classmap" array to look up the right class.
class Photo extends Eloquent {
protected $types = [
'order' => 'App\Store\Order',
'staff' => 'App\Users\Staff'
];
public function imageable()
{
return $this->morphTo();
}
public function getImageableTypeAttribute($type) {
// transform to lower case
$type = strtolower($type);
// to make sure this returns value from the array
return array_get($this->types, $type, $type);
// for Laravel5.7 or later
return \Arr::get($this->types, $type, $type);
// which is always safe, because new 'class'
// will work just the same as new 'Class'
}
}
Note that you still will need the morphClass
attribute for querying from the other side of the relation though.
When using Laravel 5.2 (or newer) you can use the new feature morphMap
to address this issue. Just add this to the boot
function in app/Providers/AppServiceProvider
:
Relation::morphMap([
'post' => \App\Models\Post::class,
'video' => \App\Models\Video::class,
]);
More about that: https://nicolaswidart.com/blog/laravel-52-morph-map
There are 2 easy ways - one below, other one in @lukasgeiter's answer as proposed by Taylor Otwell, which I definitely suggest checking as well:
// app/config/app.php or anywhere you like
'aliases' => [
...
'MorphOrder' => 'Some\Namespace\Order',
'MorphStaff' => 'Maybe\Another\Namespace\Staff',
...
]
// Staff model
protected $morphClass = 'MorphStaff';
// Order model
protected $morphClass = 'MorphOrder';
done:
$photo = Photo::find(5);
$photo->imageable_type; // MorphOrder
$photo->imageable; // Some\Namespace\Order
$anotherPhoto = Photo::find(10);
$anotherPhoto->imageable_type; // MorphStaff
$anotherPhoto->imageable; // Maybe\Another\Namespace\Staff
I wouldn't use real class names (Order
and Staff
) to avoid possible duplicates. There's very little chance that something would be called MorphXxxx
so it's pretty secure.
This is better than storing namespaces (I don't mind the looks in the db, however it would be inconvenient in case you change something - say instead of App\Models\User
use Cartalyst\Sentinel\User
etc) because all you need is to swap the implementation through aliases config.
However there is also downside - you won't know, what the model is, by just checking the db - in case it matters to you.