Returning null instead of "Call to undefined relationship" error for Laravel relationships

Viewed 383

When I use ModelName::with('somerelation')->get() with Laravel Eloquent, if the model doesn't have this relationship I get Call to undefined relationship [somerelation] on model [App\SomeModel] error.

But for polymorphic relations, I get collection of all related models and I would like to use with('somerelation') and get null if relationship is not defined. Is there any way to avoid error and return null from with() or any way to use with conditionally?

2 Answers

What I do on all my Laravel projects is creating a Model class that extends Eloquent Model and all my models will extend my Model class, so I can override some methods from Eloquent Model using my rules.

So you can create a new class (I call it Model) and override the method with with a try/catch block retuning null in the case this exception is thrown by eloquent model.

Example:

namespace App;

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\RelationNotFoundException;

abstract class Model extends EloquentModel
{
    public static function with($relations)
    {
        try {
            return parent::with($relations);
        } catch (RelationNotFoundException $e) {
            return null;
        }
    }
}

Previous answer by @Leonardo Oberle doesn't work for me. I was struggling by finding a way how to validate the integrity of a relationship string passed to the with() method, so it will load relation only upon it exists, and will not throw errors if something is missing.

So, I ended up creating a abstract Model class which extends from EloquentModel and overwrites the with() method as in Leonardo Oberle's response.

The only thing is that the method's code should look like :

namespace App;

use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\RelationNotFoundException;

abstract class Model extends EloquentModel
{
    public static function with($relations)
    {
        $filteredRelations = $this->relationExistsUntil($relations);

        parent::with($filteredRelations);

    }
}


    /**
     * @param string $with
     * @return string
     */
    protected function relationExistsUntil(string $with): string
    {
        $model = $this;
        $result = '';
        $relationParts = explode('.', $with);

        foreach ($relationParts as $relationPart) {
            $isValidRelation = method_exists($model, $relationPart) && $model->{$relationPart}() instanceof Relation;

            if (!$isValidRelation) {
                break;
            }

            $result .= empty($result) ? $relationPart : ".$relationPart";
            $model = ($model->{$relationPart}()->getRelated());
        }

        return $result;
    }



So, with that, if you will try smth like


`$user->with('relation1.relation2.relation3');`
where `relation2` doesn't exist, it will load only `relation1` and the rest will be skipped, and no exceptions/errors would be thrown.

Just don't forget to make all models then extend from that new abstract class.
Related