20 Laravel Eloquent tips and tricks

Eloquent ORM seems to be a simple mechanism, but behind the scenes, there are many semi hidden functions and little-known methods to achieve more functions. In this article, I'll show you some tips.

1. Increment and decrement

Instead of the following implementation:

$article = Article::find($article_id);
$article->read_count++;
$article->save();

You can do this:

$article = Article::find($article_id);
$article->increment('read_count');

The following methods can also be implemented:

Article::find($article_id)->increment('read_count');
Article::find($article_id)->increment('read_count', 10); // +10
Product::find($produce_id)->decrement('stock'); // -1

2. Execute the X method first. If the X method fails, execute the Y method

Eloquent has quite a number of functions that can combine the two methods, such as "please execute method X first, and if the execution of method X is unsuccessful, execute method Y".

Example 1 – findOrFail():

To override the implementation of the following code:

$user = User::find($id);
if (!$user) { abort (404); }

You can write this:

$user = User::findOrFail($id);
Example 2 – firstOrCreate():

To override the implementation of the following code:

$user = User::where('email', $email)->first();
if (!$user) {
  User::create([
    'email' => $email
  ]);
}

This is enough:

$user = User::firstOrCreate(['email' => $email]);

3. boot () method of the model

In an Eloquent model, there is a magical place called boot(), where you can override the default behavior:

class User extends Model
{
    public static function boot()
    {
        parent::boot();
        static::updating(function($model)
        {
            // Write a log or something
            // Override some attributes, such as $model - > something = transform ($something);
        });
    }
}

Setting the values of some fields when creating model objects is probably one of the most popular examples. Let's take a look at what you should do when you want to generate UUID fields when creating model objects.

public static function boot()
{
  parent::boot();
  self::creating(function ($model) {
    $model->uuid = (string)Uuid::generate();
  });
}

4. Association between conditions and sorting

General way to define association relationship:

public function users() {
    return $this->hasMany('App\User');
}

You know what? You can also add where or orderBy to the above?
For example, if you want to associate certain types of users and use the email field to sort, you can do this:

public function approvedUsers() {
    return $this->hasMany('App\User')->where('approved', 1)->orderBy('email');
}

5. Model characteristics: time, addition, etc

The Eloquent model has some parameters in the form of class attributes. The most commonly used are:

class User extends Model {
    protected $table = 'users';
    protected $fillable = ['email', 'password']; // Fields that can be assigned in batches. For example, fields can be used when User::create() is added
    protected $dates = ['created_at', 'deleted_at']; // Field name to be maintained by Carbon
    protected $appends = ['field1', 'field2']; // When json returns, the additional fields
}

Not only that, but also:

protected $primaryKey = 'uuid'; // Replace primary key
public $incrementing = false; // Set no self growth
protected $perPage = 25; // Define the number of pages displayed per page (default 15)
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at'; //Override time field name
public $timestamps = false; // Set the time field that does not require maintenance

There are more. I only listed some interesting features. For details, refer to the document abstract Model class for all features

6. Query multiple records by ID

Everyone knows the find() method, right?

$user = User::find(1);

I'm surprised that few people know that this method can accept an array of multiple ID s as parameters:

$users = User::find([1,2,3]);

7. WhereX

There is an elegant way to put this Code:

$users = User::where('approved', 1)->get();

Convert to this:

$users = User::whereApproved(1)->get();

Yes, you are right. Add the field name as a suffix to where, and it can run by magic.

In addition, there are some predefined methods related to time in Eloquent:

User::whereDate('created_at', date('Y-m-d'));
User::whereDay('created_at', date('d'));
User::whereMonth('created_at', date('m'));
User::whereYear('created_at', date('Y'));

8. Sort by relationship

A more complex "skill". Do you want to sort the forum topics according to the latest posts? The latest updated topics in the forum are very common requirements at the front, right?

First, define a separate relationship for the latest post on the topic:

public function latestPost()
{
    return $this->hasOne(\App\Post::class)->latest();
}

Then, in the controller, we can realize this "magic":

$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');

9. Eloquent::when() – if else is no longer used

Many people like to use "if else" to write query conditions, such as:

if (request('filter_by') == 'likes') {
    $query->where('likes', '>', request('likes_amount', 0));
}
if (request('filter_by') == 'date') {
    $query->orderBy('created_at', request('ordering_rule', 'desc'));
}

There is a better way – use when()

$query = Author::query();
$query->when(request('filter_by') == 'likes', function ($q) {
    return $q->where('likes', '>', request('likes_amount', 0));
});
$query->when(request('filter_by') == 'date', function ($q) {
    return $q->orderBy('created_at', request('ordering_rule', 'desc'));
});

It may not look very elegant, but its powerful function is to pass parameters:

$query = User::query();
$query->when(request('role', false), function ($q, $role) {
    return $q->where('role_id', $role);
});
$authors = $query->get();

10. One to many return the default model object

Suppose there is a situation where the author of the article is to be displayed, and the template code is:

{{ $post->author->name }}

However, if the author's information is deleted or not set for some reason. The code will return an error, such as "property of non object".

Of course, you can do this:

{{ $post->author->name ?? '' }}

You can do this through the Eloquent relationship:

public function author()
{
    return $this->belongsTo('App\Author')->withDefault();
}

In this example, if the text has no author information, author() will return an empty App\Author model object.

Furthermore, we can also assign default values to the attributes in the default model object.

public function author()
{
    return $this->belongsTo('App\Author')->withDefault([
        'name' => 'Guest Author'
    ]);
}

11. Sort by assignment function

Imagine you have this Code:

function getFullNameAttribute()
{
  return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
}

Now, do you want to sort by "full_name"? It is found that there is no effect:

$clients = Client::orderBy('full_name')->get(); //No effect

The solution is simple. We need to sort the results after getting the results

$clients = Client::get()->sortBy('full_name'); // success!

Note that the method name is different - it is not orderBy, but sortBy

12. Default sorting under global scope

What if you want User::all() to always sort by name field? You can assign it a global scope. Let's go back to boot(), the method we mentioned above:

protected static function boot()
{
    parent::boot();

    // Sort by name in positive order
    static::addGlobalScope('order', function (Builder $builder) {
        $builder->orderBy('name', 'asc');
    });
}

13. Native query method

Sometimes we need to add native queries to Eloquent statements. Fortunately, there is such a method.

// whereRaw
$orders = DB::table('orders')
    ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
    ->get();
// havingRaw
Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();
// orderByRaw
User::where('created_at', '>', '2016-01-01')
  ->orderByRaw('(updated_at - created_at) desc')
  ->get();

14. Copy: copy a copy of a row

It's simple. The description is not very thorough. The following is the best way to copy database entities (a piece of data):

$task = Tasks::find(1);
$newTask = $task->replicate();
$newTask->save();

15. Chunk data of chunk () method

It is not completely related to Eloquent. It is more about Collection, but it is still very useful for dealing with large data sets. You can use chunk () to divide this data into small data blocks

Before modification:

$users = User::all();
foreach ($users as $user) {
    // ...

You can do this:

User::chunk(100, function ($users) {
    foreach ($users as $user) {
        // ...
    }
});

16. Create something extra when creating a model

We all know Artisan commands:

php artisan make:model Company

However, do you know that there are three useful tags that can generate relevant files for the model?

php artisan make:model Company -mcr

-m will create a migration file

-c will create a controller

-r indicates that the controller should be a resource controller

17. Specify updated when calling the save method_ at

Did you know that the - > Save () method can accept parameters? We can prevent its default behavior by passing in parameters: updated_ The value of at is the current timestamp.

$product = Product::find($id);
$product->updated_at = '2019-01-01 10:00:00';
$product->save(['timestamps' => false]);

In this way, we successfully specified updated when saving_ The value of at.

18. What is the result of update()?

Do you want to know what this code actually returns?

$result = $products->whereNull('category_id')->update(['category_id' => 2]);

I mean, the update operation is performed in the database, but what does $result contain?

The answer is the affected row. So if you want to check how many rows are affected, you don't need to call anything else - the update() method will return this number to you.

19. Convert parentheses to Eloquent query

If you have a mixed and and or SQL query, like this:

... WHERE (gender = 'Male' and age >= 18) or (gender = 'Female' and age >= 65)

How to translate it with Eloquent? The following is a wrong way:

$q->where('gender', 'Male');
$q->orWhere('age', '>=', 18);
$q->where('gender', 'Female');
$q->orWhere('age', '>=', 65);

The order is not right. The correct opening method is a little more complicated, using closures as subqueries:

$q->where(function ($query) {
    $query->where('gender', 'Male')
        ->where('age', '>=', 18);
})->orWhere(function($query) {
    $query->where('gender', 'Female')
        ->where('age', '>=', 65);
})

20. orWhere of complex parameter

Finally, you can pass the array parameter to orWhere(). Usual way:

$q->where('a', 1);
$q->orWhere('b', 2);
$q->orWhere('c', 3);

You can do this:

$q->where('a', 1);
$q->orWhere(['b' => 2, 'c' => 3]);

I'm sure there are more hidden secrets, but I hope at least some of them are new to you.

Tags: Laravel

Posted on Mon, 22 Nov 2021 12:33:30 -0500 by tilde