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');
}