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()
.“常规”方式:
你可以这样做:
如