Laravel Проверьте, существует ли родственная модель

У меня есть модель 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> - это код, который я ищу.

Ответ 1

В php 7. 2+ нельзя использовать count для объекта отношения, поэтому не существует универсального метода для всех отношений. Вместо этого используйте метод запроса как @tremby, представленный ниже:

$model->relation()->exists()

универсальное решение, работающее со всеми типами отношений (pre 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

Ответ 2

A Объект привязки передает неизвестные вызовы методов через Запрос запросов, который настроен только для выбора связанных объектов. Этот 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, который для вас создал Largvel (получение связанного объекта/объекта).

Использование метода count объекта отношения (т.е. с использованием круглых скобок) будет намного быстрее, чем выполнение $model->relation->count() или count($model->relation) (если только отношение уже не было загружено), поскольку оно запускает счетчик вместо того, чтобы вытаскивать все данные для любых связанных объектов из базы данных, просто чтобы подсчитать их. Аналогично, при использовании exists не нужно выводить данные модели.

Оба exists() и count() работают над всеми типами отношений, которые я пробовал, поэтому не менее belongsTo, hasOne, hasMany и belongsToMany.

Ответ 3

Я предпочитаю использовать метод exists:

RepairItem::find($id)->option()->exists()

чтобы проверить, существует ли соответствующая модель или нет. Он отлично работает на Laravel 5.2

Ответ 4

После Php 7.1 принятый ответ не будет работать для всех типов отношений.

Поскольку в зависимости от типа отношения, Eloquent возвращает Collection, Model или Null. А в Php 7.1 count(null) выдаст error.

Итак, чтобы проверить, существует ли отношение, вы можете использовать:

Для одиночных отношений: например, hasOne и belongsTo

if(!is_null($model->relation)) {
   ....
}

Для множественных отношений: Например: hasMany и belongsToMany

if ($model->relation->isNotEmpty()) {
   ....
}

Ответ 5

Не уверен, что это изменилось в Laravel 5, но принятый ответ с использованием count($data->$relation) не работал у меня, поскольку сам акт доступа к свойству отношения вызвал его загрузку.

В конце концов, простой isset($data->$relation) помогло.

Ответ 6

Вы можете использовать метод отношениеLoaded для объекта модели. Это спасло мой бекон, поэтому, надеюсь, это помогает кому-то другому. Я был учитывая это предложение, когда я задал тот же вопрос о Laracasts.

Ответ 7

Как уже сказал Хемерсон Варела в 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 = $model->option()->create();
   }

   $option->someAttribute = temp;
   $option->save();
};

Но это лишнее. Нет необходимости проверять, существует ли связь, чтобы определить, следует ли вам update или create вызов. Просто используйте метод updateOrCreate. Это эквивалентно приведенному выше:

$model = RepairItem::find($id);
if (!empty($temp = $request->input('option'))) {  
   $model->option()
         ->updateOrCreate(['repair_item_id' => $model->id],
                          ['option' => $temp]);
}

Ответ 8

Вы сказали, что хотите проверить, существует ли отношение, поэтому вы можете update или create. Однако это не является необходимым из-за метода updateOrCreate.

Просто сделай это:

$model = RepairItem::find($id);
$model->option()
      ->updateOrCreate(['repair_item_id' => $model->id],['option' => 'A']);