A one-to-one polymorphic relation is similar to a simple one-to-one relation; however, the target model can belong to more than one type of model on a single association. For example, a blog Post
and a User
may share a polymorphic relation to an Image
model.
Using a one-to-one polymorphic relation allows you to have a single list of unique images that are used for both blog posts and user accounts. First, let's examine the table structure:
posts
id - integer
name - string
users
id - integer
name - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string
Take note of the imageable_id
and imageable_type
columns on the images
table. The imageable_id
column will contain the ID value of the post or user, while the imageable_type
column will contain the class name of the parent model. The imageable_type
column is used by Eloquent to determine which "type" of parent model to return when accessing the imageable
relation.
Next, let's examine the model definitions needed to build this relationship:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
/**
* Get the owning imageable model.
*/
public function imageable()
{
return $this->morphTo();
}
}
class Post extends Model
{
/**
* Get the post's image.
*/
public function image()
{
return $this->morphOne('App\Models\Image', 'imageable');
}
}
class User extends Model
{
/**
* Get the user's image.
*/
public function image()
{
return $this->morphOne('App\Models\Image', 'imageable');
}
}
Retrieving The Relationship
Once your database table and models are defined, you may access the relationships via your models. For example, to retrieve the image for a post, we can use the image
dynamic property:
$post = App\Models\Post::find(1);
$image = $post->image;
You may also retrieve the parent from the polymorphic model by accessing the name of the method that performs the call to morphTo
.
In our case, that is the imageable
method on the Image
model. So, we will access that method as a dynamic property:
$image = App\Models\Image::find(1);
$imageable = $image->imageable;
The imageable
relation on the Image
model will return either a Post
or User
instance, depending on which type of model owns the image.
If you need to specify custom type
and id
columns for the morphTo
relation, always ensure you pass the relationship name (which should exactly match the method name) as the first parameter:
/**
* Get the model that the image belongs to.
*/
public function imageable()
{
return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
}