As a developer, we often times deal with massive amount of nested relations and multi-dimensional arrays. Which also means from time to time we get hounded by some unexpected
Undefined index or
Trying to get property of a non-object errors.
For me, I often times experience this when I'm working on generating excel reports. So let me give you some real world (almost) examples..
Let's say we are creating an export excel report functionality for a helpdesk ticketing app.
We have a
$ticket model that has an
id field. It belongs to an
$approver model that has a
full_name field. So when we plot on excel sheet we want to know who is the approver of the ticket.
Somewhere in our code we will have something like:
// Assume that the array keys are the excel headings.. return [ 'ticket_id' => $ticket->id, 'approver' => $ticket->approver->full_name, ];
At first this looks all good. However, if the ticket has not yet been approved
$ticket->approver will result to
null. And since you are basically doing
null->full_name you'll get the really nasty error of
Trying to get property 'full_name' of non-object.
In reality, if
$ticket->approver is null, we want it to just return
null so the excel cell can be empty and not worry about any error.
optional(...) to the rescue!?
Yes! The magical
optional(...) helper function can help here. So we can just say:
return [ 'ticket_id' => $ticket->id, 'approver' => optional($ticket->approver)->full_name, ];
This looks quite okay already. You submit a PR and what a productive day it is, right?
But then your client decided to add another caveat. Now
$approver model belongs to a
$company model that has a
name field in it, and your client wants that added on the excel sheet too.
return [ 'ticket_id' => $ticket->id, 'approver' => optional($ticket->approver)->full_name, 'approver_company' => optional($ticket->approver)->company->name, ];
However, if for some reason
$company is not present from the approver model then we'd be back to that nasty error again. Okay so we can just wrap it in another
optional(...) right? Well, we can do that... but it does not look clean... and there is a better solution.
If you are not yet familiar with what this helper does, take a look at the official documentation here!.
Let's go ahead and change our implementation:
use Illuminate\Support\Arr; ... return [ 'ticket_id' => Arr::get($ticket, 'id'), // Apply here as well so it looks uniform :) 'approver' => Arr::get($ticket, 'approver.full_name'), 'approver_company' => Arr::get($ticket, 'approver.company.name'), ];
Now if either
$company model is not set, we do not have to worry about the nasty error. And it works seamlessly on multi-level nesting too.
Note: Obviously, the implementation will not work if the inner relation is a
Collection. That's a totally different approach when plotting on an excel cell.