skip to Main Content

In my Laravel app there are lots of and different types of relations defined over models, but in view there is a mistake, when ever some attributes are used which are in related object (like $invoice->company->name) there is no check for if that relation exist or like we get that object or not, it should be like this:

if($invoice->company){
     {{$invoice->company->name}}
}

but I skipped that check and directly accessing that attribute, the problem is that it is not in one relation, it is in every relation and I have used that at a lot of places so editing and adding check every where is not possible

I tried this:
In relation , I added a check that will check if object is returned, if not that return a default dummy object, but that is not applicable as I have to do that same in all relations definition in all models because that will fail in case of something like this:

{{$invoice->company->bank->amount}}

because in this case amount will throw that error.

I want to find a global solution, that I will create once but it handle all , I tried to make an exception handler that if I get error like Trying to get property of non-object then instead of error, just print N/A.
a single modification in base model may be or a single exception will be very helpful.

2

Answers


  1. if your php >= 8.0 you can use the null safe operator: (https://php.watch/versions/8.0/null-safe-operator)

    {{$invoice->company?->bank?->amount}}
    
    Login or Signup to reply.
  2. There are a few steps to help with your problem.

    1. Create a custom exception that will be thrown when you encounter the error "Trying to get property of non-object". This exception will then be caught and handled in your custom exception handler.
        namespace AppExceptions;
    
        use Exception;
    
        class NonObjectPropertyException extends Exception
        {
        //
        }
    
    1. Customize Laravel’s exception handling to catch the NonObjectPropertyException and return the default value "N/A" instead of throwing an error. To do this, you can modify the render method in the app/Exceptions/Handler.php file.
        // app/Exceptions/Handler.php
    
       use AppExceptionsNonObjectPropertyException;
    
       public function render($request, Exception $exception)
       {
    
        if ($exception instanceof NonObjectPropertyException) {
    
            return response()->view('errors.non_object_property', [], 500);
    
        }
    
        return parent::render($request, $exception);
    
       }
    
    1. Create a view that will display the default value ("N/A" in this case) when the exception is caught.

    2. To implement this behavior globally, modify the base model that other models extend. You can create a method in the base model that will handle attribute access for related models and throw the NonObjectPropertyException if the relation does not exist.

        // app/Models/BaseModel.php
    namespace AppModels;
    
    use IlluminateDatabaseEloquentModel;
    use AppExceptionsNonObjectPropertyException;
    
    class BaseModel extends Model
    {
        public function __get($key)
        {
            try {
                return parent::__get($key);
            } catch (Exception $e) {
                throw new NonObjectPropertyException();
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search