Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How does firstOrNew interact with polymorphic relationships
    Laravel Eloquent firstOrNew polymorphic relationships one-to-many relationships one-to-one relationships PHP


How does firstOrNew interact with polymorphic relationships


here's how `firstOrNew()` can be used with Eloquent's polymorphic relationships:

One-to-Many Polymorphic Relationships

1. Define the Polymorphic Relationship:

php
class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

class Video extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

2. Use `firstOrNew()` with Polymorphic Relationships:

php
// Create a new comment for a post
$post = Post::firstOrNew(['title' => 'New Post'], [
    'comments' => [
        ['body' => 'First comment'],
    ],
]);

if ($post->exists) {
    // Post already exists, update it if needed
    $post->update(['title' => 'Updated Post']);
} else {
    // Post does not exist, save the new post and its comment
    $post->save();
}

// Create a new comment for a video
$video = Video::firstOrNew(['title' => 'New Video'], [
    'comments' => [
        ['body' => 'First comment'],
    ],
]);

if ($video->exists) {
    // Video already exists, update it if needed
    $video->update(['title' => 'Updated Video']);
} else {
    // Video does not exist, save the new video and its comment
    $video->save();
}

In this example, we use `firstOrNew()` to check if the `Post` or `Video` model exists. If it doesn't, we create a new instance and associate a new `Comment` with it using the polymorphic relationship.

One-to-One Polymorphic Relationships

The process is similar for one-to-one polymorphic relationships, but you would use the `morphOne()` method instead of `morphMany()`:

php
class User extends Model
{
    public function avatar()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

class Post extends Model
{
    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

// Create a new user with an avatar
$user = User::firstOrNew(['name' => 'John Doe'], [
    'avatar' => [
        'url' => 'avatar.jpg',
    ],
]);

if ($user->exists) {
    // User already exists, update it if needed
    $user->update(['name' => 'Updated Name']);
} else {
    // User does not exist, save the new user and its avatar
    $user->save();
}

// Create a new post with an image
$post = Post::firstOrNew(['title' => 'New Post'], [
    'image' => [
        'url' => 'post-image.jpg',
    ],
]);

if ($post->exists) {
    // Post already exists, update it if needed
    $post->update(['title' => 'Updated Post']);
} else {
    // Post does not exist, save the new post and its image
    $post->save();
}

The key points are:

1. Define the polymorphic relationship using `morphTo()`, `morphOne()`, or `morphMany()`.
2. When using `firstOrNew()`, include the related model attributes in the second argument.
3. Check the `$model->exists` property to determine if the model was just created or already existed.
4. Save the model and its related polymorphic model(s) as needed.

This allows you to efficiently create or update models and their associated polymorphic relationships using a single method call.

Citations:
[1] https://stackoverflow.com/questions/40911409/laravel-5-how-to-use-firstornew-with-additional-relationship-fields
[2] https://laravel.com/docs/11.x/eloquent-relationships
[3] https://www.youtube.com/watch?v=zK6wsIAlMdI
[4] https://laravel.com/docs/5.7/eloquent-relationships
[5] https://blog.logrocket.com/polymorphic-relationships-laravel/