Laravel проверяет, существует ли связанная модель
У меня есть красноречивая модель, которая имеет связанную модель:
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>
- код, который я ищу.
8 answers
В php 7.2+ вы не можете использовать count
для объекта отношения, поэтому для всех отношений не существует универсального метода. Вместо этого используйте метод запроса, как указано ниже @tremby:
$model->relation()->exists()
Универсальное решение, работающее со всеми типами отношений ( до php 7.2):
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
Ко-многим отношениям: 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
Объект отношения передает вызовы неизвестных методов в Выразительный конструктор запросов, который настроен только на выбор связанных объектов. Этот конструктор, в свою очередь, передает вызовы неизвестных методов своему базовому построителю запросов.
Это означает, что вы можете использовать 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
, который получатель магических свойств настроил для вас Laravel (получение связанного объекта/объектов).
Использование метода count
для объекта отношения (то есть использование круглых скобок) будет намного быстрее, чем выполнение $model->relation->count()
или count($model->relation)
(если только отношение уже не было загружено с нетерпением), так как он выполняет запрос count, а не извлекает все данные для любых связанных объектов из базы данных, просто для их подсчета. Аналогично, при использовании exists
не нужно тянуть данные модели также.
И exists()
, и count()
работают со всеми типами отношений, которые я пробовал, так что, по крайней мере, belongsTo
, hasOne
, hasMany
, и belongsToMany
.
Я предпочитаю использовать метод exists
:
RepairItem::find($id)->option()->exists()
Чтобы проверить, существует ли связанная модель или нет. Он отлично работает на Laravel 5.2
После Php 7.1 Принятый ответ не будет работать для всех типов отношений.
Потому что в зависимости от типа отношения, Красноречивый вернет Collection
, Model
или Null
. И в Php 7.1 count(null)
бросит error
.
Итак, чтобы проверить, существует ли связь, вы можете использовать:
Для одиночных отношений: НапримерhasOne
и belongsTo
if(!is_null($model->relation)) {
....
}
Для множественных отношений: Например: hasMany
и belongsToMany
if ($model->relation->isNotEmpty()) {
....
}
Не уверен, изменилось ли это в Laravel 5, но принятый ответ с использованием count($data->$relation)
не сработал для меня, так как сам акт доступа к свойству relation привел к его загрузке.
В конце концов, простой isset($data->$relation)
сделал для меня трюк.
Вы можете использовать метод Relationloaded для объекта модели. Это спасло мой бекон, так что, надеюсь, это поможет кому-то еще. Мне было дано это предложение, когда я задал тот же вопрос о Laracasts.
Как уже сказал Хемерсон Варела в Php 7.1 count(null)
вызовет error
и hasOne
возвращает null
, если строка не существует. Поскольку у вас есть отношение hasOne
, я бы использовал метод empty
для проверки:
$model = RepairItem::find($id);
if (!empty($temp = $request->input('option'))) {
$option = $model->option;
if(empty($option)){
$option = $user->expertise()->create();
}
$option->someAttribute = temp;
$option->save();
};
Вы сказали, что хотите проверить, существует ли уже связь, поэтому вы можете сделать update
или create
. Однако в этом нет необходимости из-за метода updateOrCreate.
Просто сделай это:
$model = RepairItem::find($id);
$model->option()
->updateOrCreate(['repair_item_id' => $model->id],['option' => 'A']);