C
C
codercat2018-01-27 13:50:06
Laravel
codercat, 2018-01-27 13:50:06

How to load different relationships for morphs relationships?

It’s even difficult for me to form a question, so it’s better to immediately look at the code example.
How to load relations depending on object type in mophs table?

class SomeModelFirst extends Model
{
    public function notes()
    {
        return $this->morphMany(App\Note::class, 'noteable');
    }

   public function relationFirst()
    {
        return $this->belongsTo(Photo::class);
    }
}

class SomeModelSecond extends Model
{
    public function notes()
    {
        return $this->morphMany(App\Note::class, 'noteable');
    }

   public function relationSecond() {
        return $this->belongsToMany(Comment::class);
   }
}

class Note extends Model
{
    public function noteable()
    {
        return $this->morphTo();
    }
}

Представим, что в таблице есть noteable_to с SomeModelFirst и SomeModelSecond

$notes = Notes::with('noteable', 'noteable.relationFirst', 'noteable.relationSecond');
// будет ошибка, т.к. у SomeModelFirst нет relationSecond и у SomeModelSecond нет relationFirst.

Как быть?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman Sokharev, 2018-01-31
@codercat

There are at least three ways to do this.
in Orthodox
in bourgeois

class Note extends Model
{
    public function second()
    {
        return $this->morphedByMany(SomeModelSecond::class, 'taggable');
    }

    public function first()
    {
        return $this->morphedByMany(SomeModelFirst::class 'taggable');
    }
}

While this does change the structure of the relationship tree, it seems like a reasonable approach.
You can still use `morphTo()` where you don't want to eager load different relationships.
docks no - personal experience and raw bits :
class SomeModelFirst extends Model
{
    public $with = ['relationFirst'];

    public function notes()
    {
        return $this->morphMany(App\Note::class, 'noteable');
    }

   public function relationFirst()
    {
        return $this->belongsTo(Photo::class);
    }
}

class SomeModelSecond extends Model
{
    public $with = ['relationSecond']

    public function notes()
    {
        return $this->morphMany(App\Note::class, 'noteable');
    }

   public function relationSecond() {
        return $this->belongsToMany(Comment::class);
   }
}

however, be aware that now these relationships will always be eagerly loaded , except when you explicitly or indirectly call newQueryWithoutRelationships . For example, the same with() method overrides the $with specified in the model.
Thus, it is possible to beat this peculiarity of the method by dropping eagerly-loaded relations
in Orthodox
in bourgeois
$notes = Notes::with('noteable');

$notesGrouped = $noted->groupBy(function($model){
    return get_class($model);
});

$notesGrouped[SomeModelFirst::class]->load('relationFirst');
$notesGrouped[SomeModelSecond ::class]->load('relationSecond');

Since objects in php are passed by reference, the models in the original $notes collection will now have the necessary relationships loaded. This way seems to be the least of the pain.
Surely there are other ways to do this. But right now I'm pretty lazy thinking about it =)

A
Alex Wells, 2018-01-27
@Alex_Wells

Well, I don't think magic will help much here. Either any noteable extends some abstract class that implements dummy relays, or separate noteable into someModelFirst(), someModelSecond() and load it according to separate conditions.
Of course, you can pervert and override the method responsible for finding the relay - but this is nonsense, you don’t need to do this =)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question