• 20 Laravel Eloquent Tips and Tricks
  • Permanent address: blog. Kbiao. Me / 2019/01/03 /…
  • Translator: KBiao

Behind the seemingly simple and easy-to-use mechanics, there are many semi-hidden features or little-known ways to implement some very useful requirements. In this article, I’ll show you some tips.

1. Increments and decreases

If this is what you normally do:

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

Try this:

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

Or maybe this is ok:

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

2. XorY method

There are many Eloquent methods that are a combination of both, fulfilling the need to do X, or else Y, Eloquent.

Case 1 findOrFail () :

You can put code like this:

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

Replace it with this:

$user = User::findOrFail($id);
Copy the code

Case 2 firstOrCreate () :

It doesn’t have to be this long:

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

That’s enough:

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

3. Boot () method of the model

There’s a magic place in the Eloquent model called Boot () where you can override default behavior:

class User extends Model
{
    public static function boot(a)
    {
        parent::boot();
        static::updating(function($model)
        {
            // Keep some logs
            $model->something = transform($something);}); }}Copy the code

Probably one of the most common examples is setting some field values when creating a model object. Let’s say you need to generate a UUID field when you create an object.

4. Relational model with condition and ranking

The usual way to define a relational model is this

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

But did you know that you can already add where or Order Derby conditions when you define the relational model? For example, if you need to define an association for a particular type of user and sort it by email, you can do this:

public function approvedUsers(a) {
    return $this->hasMany('App\User')->where('approved'.1)->orderBy('email');
}
Copy the code

5. Model attributes: timestamp, Appends, etc

The Eloquent model has some “parameters” that take the form of properties of the class. The most commonly used are probably these:

class User extends Model {
    protected $table = 'users';
    protected $fillable = ['email'.'password']; // These fields can be created directly in the model's CREATE method
    protected $dates = ['created_at'.'deleted_at']; // These fields will be converted to Carbon, which makes it easy to use the time method provided by Carbon
    protected $appends = ['field1'.'field2']; // Additional attributes attached during serialization, as defined by getXXXAttribute in the model
}
Copy the code

But there’s more:

protected $primaryKey = 'uuid'; // The primary key name of the model may not be the default ID
public $incrementing = false; // It doesn't even have to be an incremented type!
protected $perPage = 25; // Yes, you also define model collection paging parameters (default is 15)
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at'; // The default timestamp field can also be changed
public $timestamps = false; // Or not at all
Copy the code

There are even more, and I’ve only listed the most interesting ones, but look at the code for the default abstract Model class and see all the trait methods used.

6. Query multiple entity objects

You know the find () method?

$user = User::find(1);
Copy the code

I’m surprised how few people know that it can accept multiple ids as arrays:

$users = User::find([1.2.3]);
Copy the code

7. WhereX

There is an elegant way to put the following code:

$users = User::where('approved'.1)->get();
Copy the code

Change it to this:

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

Yes, you can also change the name of any field and append it to “where” as a suffix, and it will work magically (through the magic method to implement the call).

Also, there are some predefined date/time methods 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'));
Copy the code

8. Use relational model fields to sort

A more complex “trick”. What if you have posts, but want to sort them by the most recent posts? A very common requirement in a forum with a newly updated theme at the top, right?

First, define the relationship of the most recent post on the topic:

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

This can then be done in our controller using this magic method:

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

Eloquent:: When () — No more if-else

Most of the time we use if-else to implement conditional queries, code like this:

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'));
}
Copy the code

But a better approach is to use the when () method

$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'));
});
Copy the code

It may not look shorter or more elegant, but the most powerful thing is that it can pass parameters:

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

BelongsTo default model object associated

Suppose we have a Post object that belongs to an Author object, and we have the following code in the Blade template

{{ $post->author->name }}
Copy the code

But what if the author is deleted, or for some reason not set? This will result in an error, perhaps “Property of non-object”.

Of course, you can fix this error with the following code:

{{ $post->author->name ?? ' ' }}
Copy the code

But you can solve this problem in the model definition:

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

In this example, the author () association will return an empty App\ author model when there is no author associated under the post.

Further, we can set some default properties for the model.

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

11. Custom attribute sorting

Suppose you have the following code:

(Set an additional attribute ‘full_name’ when the object is returned see Tips5 model Properties: Timestamp, appends, etc.)

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

If you want to sort by full_name? The following code does not work:

$clients = Client::orderBy('full_name')->get(); / / no drops
Copy the code

The solution, of course, is very simple. We need to rank them after we get the results.


$clients = Client::get()->sortBy('full_name'); / / stability
Copy the code

Notice that the names of the two methods are different — not Derby but sortBy.

SQL statement, custom attribute is the database does not have a field of course cannot be directly used. Laravel provides many convenient operation methods for Collection. SortBy is one of them. Of course, you can also use filter and other Collection operations.

12. Default sort within the global scope

What if you want User :: All () to always be sorted by the name field? You can assign global query scopes. Let’s go back to the boot () method already mentioned above.

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

    // By default, the name field is in ascending order
    static::addGlobalScope('order'.function (Builder $builder) {
        $builder->orderBy('name'.'asc');
    });
}
Copy the code

There is more about request scope scope here.

13. Native query methods

Sometimes you need to add a native query statement to your Eloquent statement. Fortunately, it does.

// Native WHERE statement
$orders = DB::table('orders')
    ->whereRaw('price > IF(state = "TX", ? , 100). '[200])
    ->get();

// The native having statement
Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();

// Native Order Derby statement
User::where('created_at'.'>'.'2016-01-01')
  ->orderByRaw('(updated_at - created_at) desc')
  ->get();
Copy the code

(Eloquent is essentially a repository for a DB query object, so all the original query methods available on DB can be used on the same model object as Eloquent.)

Copy: Get a copy of a row of data

It’s a simple one that doesn’t require much explanation. This is the best way to generate copies of database entries.

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

15. The Chunk () method for large tables and large collections

Not exactly Eloquent, it’s more of a method provided by the Collection Collection class, but it’s still powerful — handling larger data sets that you can break up into chunks.

Don’t do this:

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

It goes like this:

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

Similar to data sharding, reduces footprint and improves performance

16. Generate additional templates as you build the model

We all know this Artisan’s order:

php artisan make:model Company
Copy the code

But did you know that it also has three useful parameter markers for generating other files associated with the model?

php artisan make:model Company -mcr
Copy the code
  • -m will create a migration file for the model
  • -c will create controller (Contriller)
  • -r will use the table. This controller should be a resourceful.

17. Rewrite the update_AT field while saving

Did you know that the – > save () method accepts arguments? Therefore, we can tell it to “ignore” updated_AT’s default filling of the current timestamp. Look at this example:

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

Here we are overwriting the update_AT field dynamically, rather than defining it in the model beforehand.

Laravel assigns timestamps to all entity classes by default, and typically specifies $timestamps = false in the model if not required

18. What is the return value of the update () method?

Have you ever wondered what result the following code returns?

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

I mean, the update statement executes correctly in the database, but what does the $result variable contain?

The answer is the affected rows. Therefore, if you need to check the number of rows affected, there is no need to call any other methods – the update () method will return this number for you.

19. Translate the parentheses in the SQL statement into the Eloquent query

Suppose you include the keyword and/or in your SQL query as follows:

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

Eloquent query This is the wrong approach:

$q->where('gender'.'Male');
$q->orWhere('age'.'> ='.18);
$q->where('gender'.'Female');
$q->orWhere('age'.'> ='.65);
Copy the code

This order is problematic. The correct method is slightly more complicated and requires closure functions as subqueries:

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

The orWhere method uses more parameters

Finally, you can pass an array to the orWhere method.

The usual usage is:

$q->where('a'.1);
$q->orWhere('b'.2);
$q->orWhere('c'.3);
Copy the code

You can do the same with the following statement:

$q->where('a'.1);
$q->orWhere(['b'= >2.'c'= >3]);
Copy the code