Laravel Check If Related Model Exists

PhpLaravelLaravel 4EloquentLaravel 5

Php Problem Overview


I have an Eloquent model which has a related model:

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

public function setOptionArrayAttribute($values)
{
    $this->option->update($values);
}

When I create the model, it does not necessarily have a related model. When I update it, I might add an option, or not.

So I need to check if the related model exists, to either update it, or create it, respectively:

$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());
    }
};

Where <related_model_exists> is the code I am looking for.

Php Solutions


Solution 1 - Php

In php 7.2+ you can't use count on the relation object, so there's no one-fits-all method for all relations. Use query method instead as @tremby provided below:

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

generic solution working on all the relation types (pre php 7.2):

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

This will work for every relation since dynamic properties return Model or Collection. Both implement ArrayAccess.

So it goes like this:

single relations: 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 relations: 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

Solution 2 - Php

A Relation object passes unknown method calls through to an Eloquent query Builder, which is set up to only select the related objects. That Builder in turn passes unknown method calls through to its underlying query Builder.

This means you can use the exists() or count() methods directly from a relation object:

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

Note the parentheses after relation: ->relation() is a function call (getting the relation object), as opposed to ->relation which a magic property getter set up for you by Laravel (getting the related object/objects).

Using the count method on the relation object (that is, using the parentheses) will be much faster than doing $model->relation->count() or count($model->relation) (unless the relation has already been eager-loaded) since it runs a count query rather than pulling all of the data for any related objects from the database, just to count them. Likewise, using exists doesn't need to pull model data either.

Both exists() and count() work on all relation types I've tried, so at least belongsTo, hasOne, hasMany, and belongsToMany.

Solution 3 - Php

I prefer to use exists method:

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

to check if related model exists or not. It's working fine on Laravel 5.2

Solution 4 - Php

After Php 7.1, The accepted answer won't work for all types of relationships.

Because depending of type the relationship, Eloquent will return a Collection, a Model or Null. And in Php 7.1 count(null) will throw an error.

So, to check if the relation exist you can use:

For relationships single: For example hasOne and belongsTo

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

For relationships multiple: For Example: hasMany and belongsToMany

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

Solution 5 - Php

You can use the relationLoaded method on the model object. This saved my bacon so hopefully it helps someone else. I was given this suggestion when I asked the same question on Laracasts.

Solution 6 - Php

As Hemerson Varela already said in Php 7.1 count(null) will throw an error and hasOne returns null if no row exists. Since you have a hasOnerelation I would use the empty method to check:

$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();
};

But this is superfluous. There is no need to check if the relation exists, to determine if you should do an update or a create call. Simply use the updateOrCreate method. This is equivalent to the above:

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

Solution 7 - Php

Not sure if this has changed in Laravel 5, but the accepted answer using count($data->$relation) didn't work for me, as the very act of accessing the relation property caused it to be loaded.

In the end, a straightforward isset($data->$relation) did the trick for me.

Solution 8 - Php

I use for single relationships: hasOne, belongsTo and morphs

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

Because if condition is null, this will be false.

For multiple relationships: hasMany, belongsToMany and morphs

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

Solution 9 - Php

I had to completely refactor my code when I updated my PHP version to 7.2+ because of bad usage of the count($x) function. This is a real pain and its also extremely scary as there are hundreds usages, in different scenarios and there is no one rules fits all..

Rules I followed to refactor everything, examples:

$x = Auth::user()->posts->find(6); (check if user has a post id=6 using ->find())

[FAILS] if(count($x)) { return 'Found'; } 
[GOOD] if($x) { return 'Found'; }

$x = Auth::user()->profile->departments; (check if profile has some departments, there can have many departments)

[FAILS] if(count($x)) { return 'Found'; }
[GOOD] if($x->count()) { return 'Found'; }

$x = Auth::user()->profile->get(); (check if user has a profile after using a ->get())

[FAILS] if(count($x)) { return 'Found'; }
[GOOD] if($x->count()) { return 'Found'; }

Hopes this can help, even 5 years after the question has been asked, this stackoverflow post has helped me a lot!

Solution 10 - Php

If you use the model class and use Eloquent ORM, then create a new method and return bool data. like

public function hasPosts(): bool
{
    return $this->posts()->exists();
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTom MacdonaldView Question on Stackoverflow
Solution 1 - PhpJarek TkaczykView Answer on Stackoverflow
Solution 2 - PhptrembyView Answer on Stackoverflow
Solution 3 - PhpHafez DivandariView Answer on Stackoverflow
Solution 4 - PhpHemerson VarelaView Answer on Stackoverflow
Solution 5 - PhpAnthonyView Answer on Stackoverflow
Solution 6 - PhpAdamView Answer on Stackoverflow
Solution 7 - PhpDave StewartView Answer on Stackoverflow
Solution 8 - PhpMaxim PaladiView Answer on Stackoverflow
Solution 9 - PhpraphjutrasView Answer on Stackoverflow
Solution 10 - PhpMD RaselView Answer on Stackoverflow