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 95

8 ответов:

на 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

A отношении объекта передает неизвестные вызовы метода через красноречивый конструктор запросов, который настроен только для выбора связанных объектов. Этот Строитель в свою очередь передает неизвестные вызовы методов через его базовый конструктор запросов.

это означает, что вы можете использовать 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, принято отвечать не будет работать для всех типов отношений.

потому что в зависимости от типа отношения, красноречивый вернет a Collection, a Model или Null. И в Php 7.1count(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']);