2022年7月1日09:44:11
原文: https://laravel-news.com/eloquent-tips-tricks
Eloquent ORM 似乎是一个简单的机制,但在底层,有很多半隐藏的功能和鲜为人知的方法来实现更多功能。在本文中,我将向您展示一些技巧。
1. 递增和递减
而不是这个:
$article = Article::find($article_id);
$article->read_count++;
$article->save();
你可以这样做:
$article = Article::find($article_id);
$article->increment('read_count');
这些也将起作用:
Article::find($article_id)->increment('read_count');
Article::find($article_id)->increment('read_count', 10); // +10
Product::find($produce_id)->decrement('stock'); // -1
2.异或法
Eloquent 有很多功能结合了两种方法,比如“请做 X,否则做 Y”。
示例 1 – findOrFail():
代替:
$user = User::find($id);
if (!$user) { abort (404); }
做这个:
$user = User::findOrFail($id);
示例 2 – firstOrCreate():
代替:
$user = User::where('email', $email)->first();
if (!$user) {
User::create([
'email' => $email
]);
}
这样做:
$user = User::firstOrCreate(['email' => $email]);
3.模型boot()方法
在 Eloquent 模型中有一个神奇的地方boot()可以覆盖默认行为:
class User extends Model
{
public static function boot()
{
parent::boot();
static::updating(function($model)
{
// do some logging
// override some property like $model->something = transform($something);
});
}
}
可能最流行的示例之一是在创建模型对象时设置一些字段值。假设您想在那一刻生成UUID 字段。
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->uuid = (string)Uuid::generate();
});
}
4. 与条件和顺序的关系
这是定义关系的典型方式:
public function users() {
return $this->hasMany('App\User');
}
但是您是否知道此时我们已经可以添加whereor orderBy?
例如,如果您想要某种类型的用户的特定关系,也通过电子邮件订购,您可以这样做:
public function approvedUsers() {
return $this->hasMany('App\User')->where('approved', 1)->orderBy('email');
}
5. 模型属性:时间戳、追加等。
Eloquent 模型有一些“参数”,以该类的属性的形式。最受欢迎的可能是这些:
class User extends Model {
protected $table = 'users';
protected $fillable = ['email', 'password']; // which fields can be filled with User::create()
protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized
protected $appends = ['field1', 'field2']; // additional values returned in JSON
}
但是等等,还有更多:
protected $primaryKey = 'uuid'; // it doesn't have to be "id"
public $incrementing = false; // and it doesn't even have to be auto-incrementing!
protected $perPage = 25; // Yes, you can override pagination count PER MODEL (default 15)
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden
public $timestamps = false; // or even not used at all
还有更多,我列出了最有趣的,更多请查看默认抽象模型类的代码并查看所有使用的特征。
6.查找多个条目
方法大家都知道find()吧?
$user = User::find(1);
我很惊讶很少有人知道它可以接受多个 ID 作为数组:
$users = User::find([1,2,3]);
7. 哪里X
有一种优雅的方式来改变它:
$users = User::where('approved', 1)->get();
进入这个:
$users = User::whereApproved(1)->get();
是的,您可以更改任何字段的名称并将其作为后缀附加到“where”,它会神奇地起作用。
此外,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. 按关系排序
一个更复杂的“技巧”。如果您有论坛主题但想通过最新帖子订购它们怎么办?论坛中很常见的要求,最后更新的主题在顶部,对吧?
首先,为有关该主题的最新帖子描述一个单独的关系:
public function latestPost()
{
return $this->hasOne(\App\Post::class)->latest();
}
然后,在我们的控制器中,我们可以做这个“魔术”:
$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');
9. Eloquent::when()——不再有 if-else
我们中的许多人使用“if-else”编写条件查询,如下所示:
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'));
}
但是有一个更好的方法——使用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'));
});
它可能不会感觉更短或更优雅,但最强大的是传递参数:
$query = User::query();
$query->when(request('role', false), function ($q, $role) {
return $q->where('role_id', $role);
});
$authors = $query->get();
10. 属于默认模型
假设您有属于 Author 的 Post 和 Blade 代码:
{{ $post->author->name }}
但是如果作者被删除,或者由于某种原因没有设置怎么办?你会得到一个错误,比如“非对象的属性”。
当然,您可以像这样阻止它:
{{ $post->author->name ?? '' }}
但是你可以在 Eloquent 关系级别上做到这一点:
public function author()
{
return $this->belongsTo('App\Author')->withDefault();
}
在此示例中,如果没有作者附加到帖子,则author()关系将返回一个空模型。App\Author
此外,我们可以将默认属性值分配给该默认模型。
public function author()
{
return $this->belongsTo('App\Author')->withDefault([
'name' => 'Guest Author'
]);
}
11. Mutator 排序
想象一下你有这个:
function getFullNameAttribute()
{
return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
}
现在,您想按那个顺序订购full_name吗?这不起作用:
$clients = Client::orderBy('full_name')->get(); // doesn't work
解决方案非常简单。我们需要在得到结果后对结果进行排序。
$clients = Client::get()->sortBy('full_name'); // works!
请注意,函数名称不同——它不是orderBy,而是sortBy。
12. 全局范围内的默认排序
如果您想User::all()始终按name字段排序怎么办?您可以分配一个全局范围。让我们回到boot()上面已经提到的方法。
protected static function boot()
{
parent::boot();
// Order by name ASC
static::addGlobalScope('order', function (Builder $builder) {
$builder->orderBy('name', 'asc');
});
}
在此处阅读有关查询范围的更多信息。
13.原始查询方法
有时我们需要在 Eloquent 语句中添加原始查询。幸运的是,有一些功能。
// 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. 复制:复制一行
短一个。没有深入的解释,这是制作数据库条目副本的最佳方法:
$task = Tasks::find(1);
$newTask = $task->replicate();
$newTask->save();
15. 大表的 Chunk() 方法
与 Eloquent 不完全相关,它更多的是关于 Collection,但仍然很强大——要处理更大的数据集,你可以将它们分成几块。
代替:
$users = User::all();
foreach ($users as $user) {
// ...
你可以做:
User::chunk(100, function ($users) {
foreach ($users as $user) {
// ...
}
});
16. 创建模型时创建额外的东西
我们都知道这个 Artisan 命令:
php artisan make:model Company
但是您知道生成模型相关文件的三个有用标志吗?
php artisan make:model Company -mcr
-m 将创建一个迁移文件
-c 将创建一个控制器
-r 表示控制器应该是足智多谋的
17. 保存时覆盖updated_at
你知道->save()方法可以接受参数吗?因此,我们可以告诉它“忽略”updated_at要填充当前时间戳的默认功能。看到这个:
$product = Product::find($id);
$product->updated_at = '2019-01-01 10:00:00';
$product->save(['timestamps' => false]);
updated_at在这里,我们用我们预定义的覆盖默认值。
18. update() 的结果是什么?
你有没有想过这段代码实际上返回了什么?
$result = $products->whereNull('category_id')->update(['category_id' => 2]);
我的意思是,更新是在数据库中执行的,但它$result包含什么?
答案是受影响的行。因此,如果您需要检查有多少行受到影响,则无需调用任何其他方法 -update()方法将为您返回此数字。
19. 将括号转换为 Eloquent 查询
如果您在 SQL 查询中有和/或混合,会怎样,如下所示:
... WHERE (gender = 'Male' and age >= 18) or (gender = 'Female' and age >= 65)
如何将其翻译成 Eloquent?这是错误的方法:
$q->where('gender', 'Male');
$q->orWhere('age', '>=', 18);
$q->where('gender', 'Female');
$q->orWhere('age', '>=', 65);
顺序将不正确。正确的方法稍微复杂一些,使用闭包函数作为子查询:
$q->where(function ($query) {
$query->where('gender', 'Male')
->where('age', '>=', 18);
})->orWhere(function($query) {
$query->where('gender', 'Female')
->where('age', '>=', 65);
})
20. orWhere 有多个参数
最后,您可以将一组参数传递给orWhere().
“常规”方式:
$q->where('a', 1);
$q->orWhere('b', 2);
$q->orWhere('c', 3);
你可以这样做:
$q->where('a', 1);
$q->orWhere(['b' => 2, 'c' => 3]);
如
Eloquent ORM 似乎是一个简单的机制,但在底层,有很多半隐藏的功能和鲜为人知的方法来实现更多功能。在本文中,我将向您展示一些技巧。
1. 递增和递减
而不是这个:
你可以这样做:
这些也将起作用:
2.异或法
Eloquent 有很多功能结合了两种方法,比如“请做 X,否则做 Y”。
示例 1 – findOrFail()
:
代替:
做这个:
示例 2 – firstOrCreate()
:
代替:
这样做:
3.模型boot()方法
在 Eloquent 模型中有一个神奇的地方boot()
可以覆盖默认行为:
可能最流行的示例之一是在创建模型对象时设置一些字段值。假设您想在那一刻生成UUID 字段。
4. 与条件和顺序的关系
这是定义关系的典型方式:
但是您是否知道此时我们已经可以添加where
or orderBy
?例如,如果您想要某种类型的用户的特定关系,也通过电子邮件订购,您可以这样做:
5. 模型属性:时间戳、追加等。
Eloquent 模型有一些“参数”,以该类的属性的形式。最受欢迎的可能是这些:
但是等等,还有更多:
还有更多,我列出了最有趣的,更多请查看默认抽象模型类的代码并查看所有使用的特征。
6.查找多个条目
方法大家都知道find()
吧?
我很惊讶很少有人知道它可以接受多个 ID 作为数组:
7. 哪里X
有一种优雅的方式来改变它:
进入这个:
是的,您可以更改任何字段的名称并将其作为后缀附加到“where”,它会神奇地起作用。
此外,Eloquent 中有一些与日期/时间相关的预定义方法:
8. 按关系排序
一个更复杂的“技巧”。如果您有论坛主题但想通过最新帖子订购它们怎么办?论坛中很常见的要求,最后更新的主题在顶部,对吧?
首先,为有关该主题的最新帖子描述一个单独的关系:
然后,在我们的控制器中,我们可以做这个“魔术”:
9. Eloquent::when()——不再有 if-else
我们中的许多人使用“if-else”编写条件查询,如下所示:
但是有一个更好的方法——使用when()
:
它可能不会感觉更短或更优雅,但最强大的是传递参数:
10. 属于默认模型
假设您有属于 Author 的 Post 和 Blade 代码:
但是如果作者被删除,或者由于某种原因没有设置怎么办?你会得到一个错误,比如“非对象的属性”。
当然,您可以像这样阻止它:
但是你可以在 Eloquent 关系级别上做到这一点:
在此示例中,如果没有作者附加到帖子,则author()
关系将返回一个空模型。App\Author
此外,我们可以将默认属性值分配给该默认模型。
11. Mutator 排序
想象一下你有这个:
现在,您想按那个顺序订购full_name
吗?这不起作用:
解决方案非常简单。我们需要在得到结果后对结果进行排序。
请注意,函数名称不同——它不是orderBy,而是sortBy。
12. 全局范围内的默认排序
如果您想User::all()
始终按name
字段排序怎么办?您可以分配一个全局范围。让我们回到boot()
上面已经提到的方法。
在此处阅读有关查询范围的更多信息。
13.原始查询方法
有时我们需要在 Eloquent 语句中添加原始查询。幸运的是,有一些功能。
14. 复制:复制一行
短一个。没有深入的解释,这是制作数据库条目副本的最佳方法:
15. 大表的 Chunk() 方法
与 Eloquent 不完全相关,它更多的是关于 Collection,但仍然很强大——要处理更大的数据集,你可以将它们分成几块。
代替:
你可以做:
16. 创建模型时创建额外的东西
我们都知道这个 Artisan 命令:
但是您知道生成模型相关文件的三个有用标志吗?
- -m 将创建一个迁移文件
- -c 将创建一个控制器
- -r 表示控制器应该是足智多谋的
17. 保存时覆盖updated_at
你知道->save()
方法可以接受参数吗?因此,我们可以告诉它“忽略”updated_at
要填充当前时间戳的默认功能。看到这个:
updated_at
在这里,我们用我们预定义的覆盖默认值。
18. update() 的结果是什么?
你有没有想过这段代码实际上返回了什么?
我的意思是,更新是在数据库中执行的,但它$result
包含什么?
答案是受影响的行。因此,如果您需要检查有多少行受到影响,则无需调用任何其他方法 -update()
方法将为您返回此数字。
19. 将括号转换为 Eloquent 查询
如果您在 SQL 查询中有和/或混合,会怎样,如下所示:
如何将其翻译成 Eloquent?这是错误的方法:
顺序将不正确。正确的方法稍微复杂一些,使用闭包函数作为子查询:
20. orWhere 有多个参数
最后,您可以将一组参数传递给orWhere()
.“常规”方式:
你可以这样做:
如