@codercat

Как загрузить разные отношения для morphs отношений?

Мне даже сложно сформировать вопрос, поэтому лучше сразу смотреть пример кода.
Как загрузить отношения в зависимости от типа объекта в mophs таблице?

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.

Как быть?
  • Вопрос задан
  • 185 просмотров
Решения вопроса 1
greabock
@greabock
Могу
Есть, по крайней мере, три способа сделать это.

1) Использовать `morphedByMany`
на православном
на буржуйском
class Note extends Model
{
    public function second()
    {
        return $this->morphedByMany(SomeModelSecond::class, 'taggable');
    }

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

Notes::with('first.relationFirst',  'second.relationSecond');

Хотя это и приводит к изменению структуры дерева отношений, этот способ кажется вполне разумным.
Вы можете по прежнему использовать `morphTo()` там, где не требуется жадная загрузка различных отношений.

2) Использование глобальной жадной загрузки
доки нет - личный опыт и кусочки сырцов:

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

однако, следует понимать что теперь эти связи будут загружаться жадно всегда, за исключением тех случаев, когда вы явно или косвенно вызываете newQueryWithoutRelationships . Например тот же самый метод with() перекрывает $with указанный в модели.
Таким образом, можно обыграть эту особенность метода, сбросив жадно-загружаемые отношения
SomeModelFirst::with([])->get();

3) Ручная группировка коллекций.
на православном
на буржуйском
$notes = Notes::with('noteable');

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

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

Так как объекты в php передаются по ссылке, в моделях исходной коллекции $notes теперь будут загружены необходимые отношения. Этот способ кажется наименьшей болью.

Наверняка найдутся и иные способы сделать это. Но прямо сейчас мне довольно лениво думать об этом =)
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Alex_Wells
@Alex_Wells
PHP/Kotlin
Ну, думаю магия тут не сильно поможет. Либо любой noteable экстендит какой-то абстрактный класс, реализующий dummy релейшены, либо разделяй noteable на someModelFirst(), someModelSecond() и прогружай по отдельным условиям.

Конечно же, можно извратится и оверрайднуть метод, отвечающий за поиск релейшена - но это бред, так делать не нужно =)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы