- 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