У меня есть модель Eloquent, у которой есть соответствующая модель:
public function option() { return $this->hasOne('RepairOption', 'repair_item_id'); } public function setOptionArrayAttribute($values) { $this->option->update($values); }
когда я создаю модель, она не обязательно имеет связанную модель. Когда я его обновляю, я могу добавить опцию или нет.
Поэтому мне нужно проверить, существует ли соответствующая модель, либо обновить ее, либо создать ее соответственно:
$model = RepairItem::find($id); if (Input::has('option')) { if (<related_model_exists>) { $option = new RepairOption(Input::get('option')); $option->repairItem()->associate($model); $option->save(); $model->fill(Input::except('option'); } else { $model->update(Input::all()); } };
Где <related_model_exists>
– это код, который я ищу.
Хорошо, так как @TheShiftExchange не принял совета, там мы идем с общим решением, работающим на всех типах отношений:
if (count($model->relation)) { // exists }
Это будет работать для каждого отношения, так как динамические свойства возвращают Model
или Collection
. Оба реализуют ArrayAccess
.
Так оно и происходит:
одиночные отношения: hasOne
/ принадлежит belongsTo
/ morphTo
/ morphOne
// no related model $model->relation; // null count($model->relation); // 0 evaluates to false // there is one $model->relation; // Eloquent Model count($model->relation); // 1 evaluates to true
to-many: hasMany
/ принадлежит belongsToMany
/ morphMany
/ morphToMany
/ morphedByMany
// no related collection $model->relation; // Collection with 0 items evaluates to true count($model->relation); // 0 evaluates to false // there are related models $model->relation; // Collection with 1 or more items, evaluates to true as well count($model->relation); // int > 0 that evaluates to true
Первое предложенное решение не будет работать для прежних отношений, так как на модели нет методов count()
, и простая if ($model->relation)
не будет оцениваться как false для любого из последних соотношений, так как существует всегда Коллекция. И это, даже пустое, всегда оценивает true
.
Объект Relation передает неизвестные вызовы методов в конструктор запросов Eloquent , который настроен только для выбора связанных объектов. Этот Builder, в свою очередь, передает неизвестные вызовы методов в свой базовый запрос Builder .
Это означает, что вы можете использовать методы exists()
или count()
непосредственно из объекта отношения:
$model->relation()->exists(); // bool: true if there is at least one row $model->relation()->count(); // int: number of related rows
Обратите внимание на круглые скобки после relation
: ->relation()
– вызов функции (получение объекта отношения), а не ->relation
которое для вас создал Lizardvel (получение связанного объекта / объекта).
Использование метода count
объекта отношения (т. Е. Использование круглых скобок) будет намного быстрее, чем использование отношения $model->relation->count()
или count($model->relation)
(если отношение уже не было желательным – загружен), поскольку он запускает запрос на подсчет, а не вытягивает все данные для любых связанных объектов из базы данных, просто чтобы подсчитать их. Аналогичным образом, использование exists
файла не обязательно должно выводить данные модели.
Both exists()
и count()
работают над всеми типами отношений, которые я пробовал, поэтому, по крайней мере, принадлежит belongsTo
, hasOne
, hasMany
и принадлежит belongsToMany
.
Я предпочитаю использовать exists
метод:
RepairItem::find($id)->option()->exists()
чтобы проверить, существует ли соответствующая модель или нет. Он отлично работает на Laravel 5.2
Не уверен, что это изменилось в Laravel 5, но принятый ответ с использованием count($data->$relation)
не работал для меня, так как сам процесс доступа к свойству отношения вызвал его загрузку.
В конце концов, простой isset($data->$relation)
сделал для меня трюк.
Вы можете использовать метод relativeLoaded для объекта модели. Это спасло мой бекон, поэтому, надеюсь, это помогает кому-то другому. Мне дали это предложение, когда я задал тот же вопрос о Laracasts.