Laravel verifica se o modelo relacionado existe

Eu tenho um modelo Eloquent que possui um modelo relacionado:

public function option() { return $this->hasOne('RepairOption', 'repair_item_id'); } public function setOptionArrayAttribute($values) { $this->option->update($values); } 

Quando crio o modelo, ele não possui necessariamente um modelo relacionado. Quando eu atualizá-lo, eu posso adicionar uma opção, ou não.

Então eu preciso verificar se o modelo relacionado existe, para atualizá-lo ou criá-lo, respectivamente:

 $model = RepairItem::find($id); if (Input::has('option')) { if () { $option = new RepairOption(Input::get('option')); $option->repairItem()->associate($model); $option->save(); $model->fill(Input::except('option'); } else { $model->update(Input::all()); } }; 

Onde é o código que estou procurando.

Ok, então, uma vez que @TheShiftExchange não tomou o conselho, lá vamos com solução genérica trabalhando em todos os tipos de relação:

 if (count($model->relation)) { // exists } 

Isso funcionará para cada relação, uma vez que propriedades dinâmicas retornam Model ou Collection . Ambos implementam ArrayAccess .

Então é assim:

relações únicas: 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 

para-muitas relações: tem muitos / morphMany / morphToMany / morphedByMany / 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 primeira solução sugerida não funcionaria para as relações anteriores, uma vez que não há methods de count() no modelo e simples if ($model->relation) não se avaliarem para falso para qualquer uma das últimas relações, já que existe sempre uma coleção. E isso, mesmo vazio, sempre avalia como true .

Um object de Relação passa chamadas de método desconhecido para um Construtor de consulta Eloquent , que é configurado para selecionar apenas os objects relacionados. Esse Construtor, por sua vez, passa as chamadas de método desconhecido para seu Construtor de consulta subjacente.

Isso significa que você pode usar os methods exists() ou count() diretamente de um object de relação:

 $model->relation()->exists(); // bool: true if there is at least one row $model->relation()->count(); // int: number of related rows 

Observe os parênteses após a relation : ->relation() é uma chamada de function (obtendo o object de relação), em oposição a ->relation que um getter de propriedade mágico configurado para você por Laravel (obtendo o object / objects relacionados).

O uso do método de count no object de relação (ou seja, usando os parênteses) será muito mais rápido do que fazer $model->relation->count() ou count($model->relation) (a menos que a relação já tenha sido ansiosa- carregado), uma vez que executa uma consulta de contagem, em vez de puxar todos os dados para quaisquer objects relacionados do database, apenas para contabilizá-los. Da mesma forma, o uso exists não precisa extrair os dados do modelo.

Ambos exists() e count() trabalham em todos os tipos de relação que eu tentei, então, pelo menos, hasOne , hasOne , tem hasOne e hasOne .

Eu prefiro usar o método exists :

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

para verificar se o modelo relacionado existe ou não. Está funcionando bem no Laravel 5.2

Não tenho certeza se isso mudou no Laravel 5, mas a resposta aceita usando count($data->$relation) não funcionou para mim, pois o próprio ato de acessar a propriedade de relação causou a carga.

No final, um resultado direto isset($data->$relation) fez o truque para mim.

Você pode usar o método relationLoaded no object do modelo. Isso salvou meu bacon, então espero que ajude alguém. Foi dada essa sugestão quando fiz a mesma pergunta sobre Laracast.