How to use Advanced Laravel Eloquent

2018-06-12 07:08 AM

166

Advanced Laravel Eloquent usage. Laravel makes building PHP applications a breeze. It is designed to provide methods for handling the basics your application will need to run – database interaction, routing, sessions, caching and more. It has service providers that allow you load custom configurations and extend Laravel’s capabilities to suit your needs.

Laravel makes building PHP applications a breeze. It is designed to provide methods for handling the basics your application will need to run – database interaction, routing, sessions, caching and more. It has service providers that allow you load custom configurations and extend Laravel’s capabilities to suit your needs.

In this guide, we are going to dig deep into the ORM (object relational mapper) Laravel uses: Eloquent. We will throw some light on some less used features of Eloquent and how it can make your development process even easier.

Requirements

To follow along in this tutorial you must:

Have a working knowledge of PHP.

Have basic to intermediate knowledge of the Laravel framework.

Be familiar with Eloquent and its syntax.

A sample working Laravel project to play with is optional but recommended.

What is Eloquent?

The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation (closely resembling that of Ruby on Rails) for working with your database. Each Eloquent model creates a wrapper around the database table associated with it. This makes every instance of the Eloquent model a representation of a row on the associated table.

Eloquent provides accessor methods and properties corresponding to each table cell on the row. It also provides methods for establishing relationships with other models and enables you to access these models through that relationship.

Updating an Eloquent model instance updates the database record it is mapped to, and deleting it also deletes the record.

Eloquent also provides a lot of features for working with your database records. We will be exploring a few of them in this article like:

Using Eloquent accessors

Accessors allow you format a value retrieved from the database in a certain way. For example, your app issues tracking codes for orders that all have the prefix – ‘Acme_’. You may create a string field and prepend your company initials to all generated codes before storing them. But that would make your database break the normalization code.

To ensure that when you return the tracking codes to your users it follows the same pattern, you can define an accessor for accessing these codes like this:

Using Eloquent mutators

Mutators are like accessors but just work the opposite way. They are used to mutate the data stored to the database as opposed to how it is fetched. Mutators are called when you assign a value to the model property you defined the mutator on.

This mutator will be called anytime you assign a value to tracking_code, like this:

$order = \App\Order::find(1);
$order->total_cost = 24451;

💡 Like the accessors, snake cased properties will be converted to camel case and wrapped around. For example, total_cost becomes TotalCost and the mutator will be setTotalCostAttribute.

Eager loading relationships

When you are accessing an Eloquent model, the relationships for that model are not loaded by default. Laravel lazy loads the relationships when you try to access them. This is great since it saves memory used in storing all that data. However, what if you know you will need all of the relationships? Well this is where eager loading comes in.

Another advantage of eager loading is that it avoids the N+1 problem. Consider this code sample:

In the code above, we are fetching all the orders from the data store, and then in the loop we are trying to access the first_name property in the user relationship. While this code will work we will have a problem. Because the relationships are lazy loaded, every time the loop runs, a new query will be fired to get the user relationship.

What happens when you have a hundred orders? Your application will perform 101 queries to get the names of all the users behind orders. The first to get all the orders and the next to get the users for each of orders. You can see that your operation has a O(n) time complexity.

We reduce the time taken to get all the orders and users to O(1) by eager loading all the users like this:

The above code will execute two database queries. One to retrieve all the orders and the second to retrieve all the users tied to the orders. If you have 1000 order records, your application still executes just two queries.

Since we need only the user’s first name, we can choose to eager load it like this:

Eager loading is very useful if you have an API and need to return data through your API endpoint. It will present you with the entire dataset you would need, saving you from making multiple API calls to get data.

Collection methods

Whenever you run a model query to return many results, you receive an Eloquent Collection object. This collection object extends the Laravel base collection. This means it inherits dozens of methods used to fluently work with the underlying array of Eloquent models.

💡 Like the accessors, snake cased properties will be converted to camel case and wrapped around. For example, total_cost becomes TotalCost and the mutator will be setTotalCostAttribute.

For example, assume you want to retrieve only orders that have been delivered and assign a delivery status text to them, you can do the following:

This will filter out all the orders that were not done on that particular day.

💡 Like the accessors, snake cased properties will be converted to camel case and wrapped around. For example, total_cost becomes TotalCost and the mutator will be setTotalCostAttribute.

Eloquent events

Eloquent models fire several events which allows you to hook into different parts of a model’s lifecycle. The events are: retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, and restored. Every time each event occurs, you can execute a code or perform an action.

To track and react to events, you can use an observer class for the model you want to capture events on. Observers classes have method names which reflect the Eloquent events you wish to listen for. Each of these methods receives the model as their only argument.

To explore how observers work, let’s write an observer class for a make-believe User model. We will check if a user has an invite when creating the account and tag the referrer. We will also check if there is a pending order before deleting the user’s account.

First, create a directory app/observers and in there make a new PHP file UserObserver.php. In the file paste the following code:

In the observer above, we have defined operations we want to run when certain events are fired. So now we can create our controller and never have to worry about making the controller unnecessarily burdened with logic that does not concern it.

Eloquent query scopes

Scopes allow you to add constraints to all queries for a given model. Laravel has two types of scopes: global and local.

Global scopes are applied every time you call the model by default. Local scopes allow you to define common sets of constraints that you may re-use throughout your application. You use local scopes only when you need to and will not be applied every time you call the model.

An example of a global scope is softDeletes, which filters your queries to remove records you had previously marked as deleted. A place you may wish to use a global scope is with a feature like tickets where you only want to retrieve tickets that have not been closed. Let’s examine how to define this global scope.

You can either write the scope as a standalone class or defined it as a dynamic scope in the boot method of your model.

Eloquent query scopes: standalone global scope

Here’s how we can implement a standalone global scope. We could create a directory app/Scopes in our Laravel application and in that directory create a scope class as seen below:

Above, we defined a local scope on the ticket model. The scopeOpen will only return tickets that are still open while the scopeIsClosed does the opposite. You can however pass an argument to scopeIsClosed to return tickets that are either open or closed.

To use it, you do the following:

# Get only open tickets
$tickets = \App\Ticket::open()->get();
# Get only open tickets
$tickets = \App\Ticket::isClosed(&apos;false&apos;)->get();
# Get only closed tickets
$tickets = \App\Ticket::isClosed(&apos;true&apos;)->get();
# Get all tickets
$tickets = \App\Ticket::all();

Which scope you choose to define depends on the needs of your application. You can learn more here.

Conclusion

In this guide, we have considered how useful Laravel Eloquent is and how you can utilize to improve your code. They may seem confusing the first time you encounter them but once you put them into practice, it can save you a good amount of time and make your code more readable.