Laravel / Eloquent - метод настраиваемого отношения

У меня есть отчет класса, который имеет отношение ownToMany к метрике. Отчет также имеет отношение ownTo к метрике.

Обычно модель, возвращаемая отношением ownTo, совпадает с одной из моделей в отношении ownToMany. Когда это правда, я бы хотел, чтобы каждое из двух отношений фактически смотрело на один и тот же экземпляр объекта (это также экономит дополнительное путешествие в базу данных).

Итак, в общих чертах - есть ли способ заставить одно отношение сначала проверить другое, чтобы увидеть, была ли уже загружена модель, и если да, указать на этот объект, а не создавать новый.

Я попытался поместить некоторый код в метод отношения ownTo для Metric, но не могу обойти тот факт, что он должен возвращать экземпляр ownTo, которому нужны различные вещи, передаваемые в качестве аргументов конструктора (например, объект запроса), которые не уместно в том случае, если модель уже была загружена в отношение ownToMany.

Я подумал о том, чтобы отказаться от отношения ownTo и добавить данные по горизонтали в сводную таблицу для отношения ownToMany, но это не требуется отношения «многие ко многим», так что это кажется немного неправильным.

Спасибо!

Джефф


person Geoff Clayton    schedule 18.05.2015    source источник
comment
Я бы снова подумал о том, чтобы бросить belongsTo отношения. Преимущество belongsToMany в том, что он гибкий и позволяет связывать 0, 1 или несколько записей. Недостаток в том, что для управления им нужна дополнительная таблица (сводная таблица). В любом случае вам понадобится эта сводная таблица, так что просто придерживайтесь belongsToMany и избавьтесь от путаницы. Если вы настроены на оба, думаю, я понял, как делать то, что вы хотите делать.   -  person user1669496    schedule 18.05.2015
comment
Вы, вероятно, правы, но меня отталкивает то, что контекст отношения принадлежит таков, что всегда должен быть только один. Использование подхода сводной таблицы с логическим столбцом для пометки одного из отношений принадлежитToMany как особого кажется инстинктивно неправильным, поскольку ничто не мешает пометить несколько записей как особые. Только кажется немного неправильным, так что, возможно, сделаю это, поскольку я думаю, что единственный способ сделать это `` по-своему '' - это множество дополнений к Eloquent, и, поскольку я не ожидаю, что это понадобится в другом месте в приложении, это, вероятно, не стоит дополнительная сложность.   -  person Geoff Clayton    schedule 18.05.2015
comment
Если должно быть только 1, это больше похоже на belongsTo. Я отправлю быстрый ответ, который, как мне кажется, должен сработать.   -  person user1669496    schedule 18.05.2015
comment
Извините, что вернул это из мертвых, но вы можете использовать индекс UNIQUE в MySQL, чтобы обеспечить соблюдение только одной модели, отмеченной как особая.   -  person Jim Rubenstein    schedule 19.02.2016
comment
Будьте осторожны при использовании уникальных индексов при использовании мягких удалений. Они могут поймать вас, если вы не будете осторожны, поскольку уникальность не различает строки с обратимым удалением и не удаленные.   -  person Jason    schedule 20.05.2016


Ответы (1)


Идея здесь состоит в том, чтобы написать функцию, которая будет проверять, загружена ли связь, и возвращать эту связь, в противном случае она вернет belongsToMany. Это войдет в ваш Report класс. Это также для Laravel 5. Если у вас их 4, просто удалите пространства имен из названий моделей.

public function metric()
{
    return $this->belongsTo('App\Metric');
}

public function metrics()
{
    return $this->belongsToMany('App\Metric');
}

public function getMetric()
{
    if(array_key_exists('metric', $this->getRelations())) {
        return $this->metric;
    }

    return $this->metrics()->first();
}

Если вы все же решите использовать только belongsToMany, я бы посоветовал поместить в сводную таблицу уникальный ключ для обоих идентификаторов, чтобы избежать дублирования в сводной таблице.

person user1669496    schedule 18.05.2015
comment
Это близко к тому, что я использовал, но мне пришлось использовать имя метода getMetricAttribute. - person Geoff Clayton; 18.05.2015