Articles

August 26, 2021

Arr::get(...) to silence some of our errors.

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.. ## Situation... 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. No problem! ``` 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. ## Arr::get(...) If you are not yet familiar with what this helper does, take a look at the [official documentation here!](https://laravel.com/docs/8.x/helpers#method-array-get). 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 `$approver` or `$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.

July 3, 2020

3 Things You Probably Didn't Know About Form Requests

I personally think that one of the most underrated feature of Laravel is Form Request. Form Requests allows you to perform more complex authorizations and validations and can drastically clean up your controllers if you know how to use it.  Here are 3 things you probably did not know you can do with Form Requests. # 1. Removing the authorize method will make the authorization check pass. When generating Form Requests using `php artisan make:request FooRequest` command , the authorize method by default will return false. However, instead of returning true in this method, you can just delete it entirely - which achieves the same result and a much cleaner approach. # 2. Add a persist method in Form Request class to handle storing and updating of your models. Basically, we will let our form persist itself. Lets take a look at this simple blog post example: // In our PostRequest class we can have the following methods. class PostRequest { public function rules() { return [ 'title' => 'required|max:255', 'body' => 'required', ]; } public function persist(Post $post = null) // We type-hint our Post model here. { $post = $post ?? new Post; $post->title = $this->title; $post->body = $this->body; $post->save(); return $post->fresh(); } } // In our PostController we can have the store and update methods like so. class PostController extends Controller { public function store(PostRequest $request) { // You can definitely return view or redirect here, whichever you prefer. // Let's assume this is a json endpoint so we just return PostResource. return PostResource($request->persist()); } public function update(PostRequest $request, Post $post) // Route-model binding. { // We pass the post model so it will be updated in persist method. return PostResource($request->persist($post)); } } Now this cleans up the controller into single-line and we have our validation and persistence layers both within the Form Request class. # 3. Before-and-after-validation hooks you can tap into in Form Request class. If you need to do some logic before the validation runs, such as sanitizing data from the request, you can use the `prepareForValidation()` method. protected function prepareForValidation() { $this->merge([ 'slug' => Str::slug($this->slug), ]); } If you need to do some logic after the validation runs, such as performing further validations, you can use the `withValidator(...)` method. public function withValidator($validator) { $validator->after(function ($validator) { if ($this->somethingElseIsInvalid()) { $validator->errors()->add('field', 'Something is wrong with this field!'); } }); } **Bonus:** Form Request is just an instance of `Illuminate\Http\Request`. Which means whatever properties or methods you have access to using the `request()` helper, you can also access it in the Form Request class. For further information about Form Requests, visit the official Laravel documentation here: [https://laravel.com/docs/7.x/validation#form-request-validation](https://laravel.com/docs/7.x/validation#form-request-validation) Cheers!

January 6, 2019

The Illuminate Manager Class

`Illuminate\Support\Manager::class` is an abstract class that you can inherit from to assist you in constructing your own manager implementation for your drivers. This class only requires you to implement `getDefaultDriver()` method in your own class. Creating drivers can either be by using closure, or declaring a `create{DriverName}Driver` in your manager implementation. One good example of concrete implementation is Laravel's `Illuminate\Hashing\HashManager::class`, which inherits from `Manager::class` and shows you how to manage your drivers. **P.S:** I know, I know! Code to interface not inheritance. First, you can still code to interface while inheriting from this class. Also, this is just an optional approach for creating manager classes, so it's still up to you as a developer.

October 10, 2018

Dynamic Query Scopes

Long controller methods and complicated queries often times go hand in hand. One of the common reasons I see is that developers don't utilize dynamic scopes for their models enough (or at all). As a rule of thumb, whenever I find 'where' query calls that needs a callback, I usually do throw that into a scope. I find this most common when I need to do some sort of constraint on the relationship. Throwing your query calls into a scope abstracts the actual implementation, and you can just re-use the scope whenever you want. ## Example: We are developing a medical service app and we are tasked to get all the doctors having cases assigned to the current authenticated doctor and include a count of cases assigned by each doctor. Our original implementation goes like this.. use App\Models\Doctor; use Illuminate\Support\Facades\Auth; ... public function index() { return Doctor::whereHas('cases', function ($query) { $query->where('assignee_id', Auth::id()); }) ->withCount(['cases' => function ($query) { $query->where('assignee_id', Auth::id()); }]) ->get(); } This implementation isn't bad at all. However, reading this takes a while to process what this code is trying to accomplish. Also, if we are going to use the scope on other places aside from the `index()` method, it makes more sense to just extract it to a scope. Let's see how we can refactor this.. use App\Models\Doctor; use Illuminate\Support\Facades\Auth; ... public function index() { return Doctor::onlyWithCasesAssignedTo(Auth::user()) ->withCountOfCasesAssignedTo(Auth::user()) ->get(); } // Then in our Doctor model, we add couple of query scopes.. use Illuminate\Database\Eloquent\Builder; ... public function scopeOnlyWithCasesAssignedTo(Builder $query, Doctor $doctor) { return $query->whereHas('cases', function ($query) { $query->where('assignee_id', $doctor->id); }); } public function scopeWithCountOfCasesAssignedTo(Builder $query, Doctor $doctor) { return $query->withCount(['cases' => function ($query) { $query->where('assignee_id', Auth::id()); }]); } And there you go! We've successfully extracted the complicated queries from our controller to their dedicated query scope methods. Cheers!

September 19, 2018

Rendering and Reporting Exceptions

If you need a more robust reporting of your Exceptions, you can just add a report() method to your exception classes. Laravel will auto-detect that (and the render method) and run the logic inside. What's the difference between render and report in Exception classes? In render method you will typically want to return a response of some type (json/view), while report method you will typically want to Log the exception (file/database). And if you are using some 3rd party reporting tool like Sentry or Bugsnag you will want to call that in the report method as well. ``` use Exception; use Illuminate\Support\Facades\Log; class FooException extends Exception { /** * Report the exception. * * @return void */ public function report() { // Using simple Log Log::warning($this->getMessage()); // Using 3rd party integration like Sentry or Bugsnag app('sentry')->captureException($this); } } ```

Marvin Quezon · Copyright © 2026 · Privacy · Sitemap