Przypomnienie w zasadzie wszystkich relacji, jakie przerabialiśmy plus poznanie polimorficznego one of many. Do dzieła.

Rzućmy okiem na model movie i zastanówmy się, jakie ma relacje:

class Movie extends Model
{
    use HasFactory;

    protected $fillable = ["title", "director", "length", "release_date"];

    public function reviews(){
        return $this->hasMany(Review::class);
    }

    public function latestReview()
        {
            return $this->hasOne(Review::class)->latestOfMany();
        }

    public function oldestReview()
        {
            return $this->hasOne(Review::class)->oldestOfMany();
        }

        public function worstReview()
        {
            return $this->hasOne(Review::class)->ofMany('rating', 'min');
        }

        public function bestReview()
        {
            return $this->hasOne(Review::class)->ofMany('rating', 'max');
        }

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

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

Relacje movie:

  • reviews, hasMany, czyli zwykłe one to many, gdzie Movie jest rodzicem a Review dzieckem (belongsTo Movie)
  • latestReview i oldestReview, czyli has one of many
  • worstReview i bestReview, czyli has one of many z nazwą tabeli w relacji i funkcją sortującą
  • image, morphOne, czyli polimorficzne hasOne, gdzie image ma imageable morphTo (puste)
  • comments, czyli morphMany, polimorficzne hasMany, gdzie comment ma commentable morphTo (puste)

Ogarnijmy te relacje, od obu stron, potem jeszcze od stron tabel w bazie danych i jedziemy z polimorficznym has one of many (w review):

class Review extends Model
{
    use HasFactory;

    protected $fillable = ["author", "content", "rating"];

    public function movie(){
        return $this->belongsTo(Movie::class);
    }

    public function tags(){
        return $this->belongsToMany(Tag::class)->withTimestamps();
    }

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

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

    public function latestComment()
    {
        return $this->morphOne(Comment::class, 'commentable')->latestOfMany();
    }

    public function oldestComment()
    {
        return $this->morphOne(Comment::class, 'commentable')->oldestOfMany();
    }
}

Mamy tutaj:

  • movie, czyli belongsTo, odwrotna strona relacji one 2 one (hasOne)
  • tags, czyli belongsToMany, czyli relacja manyToMany, Tag również ma belongsToMany z klasą Review
  • image, morphOne, czyli poliumorficzne hasOne
  • comments, morphMany, polimorficzne hasMany
  • latestComment i oldestComment, dodaliśmy dopiero teraz, polimorficzne wersje has one of many.

To wszystko musi się w głowie ułożyć. Wykonajmy kilka ćwiczeń:

Artisan::command('r-latest-comment {id}', function (int $id) {

    $r = Review::with('latestComment')->findOrFail($id);
   

    $this->comment("Review author: {$r->author}");
    $this->comment("Movie id: {$r->movie_id}");
    $this->comment("Latest comment title: {$r->latestComment->title}");
    $this->comment("Latest comment created_at: {$r->latestComment->created_at}");

    
});

Teraz druga z naszych relacji:

Artisan::command('r-oldest-comment {id}', function (int $id) {

    $r = Review::with('oldestComment')->findOrFail($id);
   

    $this->comment("Review author: {$r->author}");
    $this->comment("Movie id: {$r->movie_id}");
    $this->comment("Oldest comment title: {$r->oldestComment->title}");
    $this->comment("Oldest comment created_at: {$r->oldestComment->created_at}");
 
});

Pobawmy się tym, jeszcze raz przeanalizujmy wszystko, aby upewnić się, że rozumiemy.