• 20 个 Laravel的orm技巧和窍门(转)


    2022年7月1日09:44:11

    原文: https://laravel-news.com/eloquent-tips-tricks

    1. Eloquent ORM 似乎是一个简单的机制,但在底层,有很多半隐藏的功能和鲜为人知的方法来实现更多功能。在本文中,我将向您展示一些技巧。
    2. 1. 递增和递减
    3. 而不是这个:
    4. $article = Article::find($article_id);
    5. $article->read_count++;
    6. $article->save();
    7. 你可以这样做:
    8. $article = Article::find($article_id);
    9. $article->increment('read_count');
    10. 这些也将起作用:
    11. Article::find($article_id)->increment('read_count');
    12. Article::find($article_id)->increment('read_count', 10); // +10
    13. Product::find($produce_id)->decrement('stock'); // -1
    14. 2.异或法
    15. Eloquent 有很多功能结合了两种方法,比如“请做 X,否则做 Y”。
    16. 示例 1 – findOrFail():
    17. 代替:
    18. $user = User::find($id);
    19. if (!$user) { abort (404); }
    20. 做这个:
    21. $user = User::findOrFail($id);
    22. 示例 2 – firstOrCreate():
    23. 代替:
    24. $user = User::where('email', $email)->first();
    25. if (!$user) {
    26. User::create([
    27. 'email' => $email
    28. ]);
    29. }
    30. 这样做:
    31. $user = User::firstOrCreate(['email' => $email]);
    32. 3.模型boot()方法
    33. 在 Eloquent 模型中有一个神奇的地方boot()可以覆盖默认行为:
    34. class User extends Model
    35. {
    36. public static function boot()
    37. {
    38. parent::boot();
    39. static::updating(function($model)
    40. {
    41. // do some logging
    42. // override some property like $model->something = transform($something);
    43. });
    44. }
    45. }
    46. 可能最流行的示例之一是在创建模型对象时设置一些字段值。假设您想在那一刻生成UUID 字段。
    47. public static function boot()
    48. {
    49. parent::boot();
    50. self::creating(function ($model) {
    51. $model->uuid = (string)Uuid::generate();
    52. });
    53. }
    54. 4. 与条件和顺序的关系
    55. 这是定义关系的典型方式:
    56. public function users() {
    57. return $this->hasMany('App\User');
    58. }
    59. 但是您是否知道此时我们已经可以添加whereor orderBy?
    60. 例如,如果您想要某种类型的用户的特定关系,也通过电子邮件订购,您可以这样做:
    61. public function approvedUsers() {
    62. return $this->hasMany('App\User')->where('approved', 1)->orderBy('email');
    63. }
    64. 5. 模型属性:时间戳、追加等。
    65. Eloquent 模型有一些“参数”,以该类的属性的形式。最受欢迎的可能是这些:
    66. class User extends Model {
    67. protected $table = 'users';
    68. protected $fillable = ['email', 'password']; // which fields can be filled with User::create()
    69. protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized
    70. protected $appends = ['field1', 'field2']; // additional values returned in JSON
    71. }
    72. 但是等等,还有更多:
    73. protected $primaryKey = 'uuid'; // it doesn't have to be "id"
    74. public $incrementing = false; // and it doesn't even have to be auto-incrementing!
    75. protected $perPage = 25; // Yes, you can override pagination count PER MODEL (default 15)
    76. const CREATED_AT = 'created_at';
    77. const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden
    78. public $timestamps = false; // or even not used at all
    79. 还有更多,我列出了最有趣的,更多请查看默认抽象模型类的代码并查看所有使用的特征。
    80. 6.查找多个条目
    81. 方法大家都知道find()吧?
    82. $user = User::find(1);
    83. 我很惊讶很少有人知道它可以接受多个 ID 作为数组:
    84. $users = User::find([1,2,3]);
    85. 7. 哪里X
    86. 有一种优雅的方式来改变它:
    87. $users = User::where('approved', 1)->get();
    88. 进入这个:
    89. $users = User::whereApproved(1)->get();
    90. 是的,您可以更改任何字段的名称并将其作为后缀附加到“where”,它会神奇地起作用。
    91. 此外,Eloquent 中有一些与日期/时间相关的预定义方法:
    92. User::whereDate('created_at', date('Y-m-d'));
    93. User::whereDay('created_at', date('d'));
    94. User::whereMonth('created_at', date('m'));
    95. User::whereYear('created_at', date('Y'));
    96. 8. 按关系排序
    97. 一个更复杂的“技巧”。如果您有论坛主题但想通过最新帖子订购它们怎么办?论坛中很常见的要求,最后更新的主题在顶部,对吧?
    98. 首先,为有关该主题的最新帖子描述一个单独的关系:
    99. public function latestPost()
    100. {
    101. return $this->hasOne(\App\Post::class)->latest();
    102. }
    103. 然后,在我们的控制器中,我们可以做这个“魔术”:
    104. $users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');
    105. 9. Eloquent::when()——不再有 if-else
    106. 我们中的许多人使用“if-else”编写条件查询,如下所示:
    107. if (request('filter_by') == 'likes') {
    108. $query->where('likes', '>', request('likes_amount', 0));
    109. }
    110. if (request('filter_by') == 'date') {
    111. $query->orderBy('created_at', request('ordering_rule', 'desc'));
    112. }
    113. 但是有一个更好的方法——使用when():
    114. $query = Author::query();
    115. $query->when(request('filter_by') == 'likes', function ($q) {
    116. return $q->where('likes', '>', request('likes_amount', 0));
    117. });
    118. $query->when(request('filter_by') == 'date', function ($q) {
    119. return $q->orderBy('created_at', request('ordering_rule', 'desc'));
    120. });
    121. 它可能不会感觉更短或更优雅,但最强大的是传递参数:
    122. $query = User::query();
    123. $query->when(request('role', false), function ($q, $role) {
    124. return $q->where('role_id', $role);
    125. });
    126. $authors = $query->get();
    127. 10. 属于默认模型
    128. 假设您有属于 Author 的 Post 和 Blade 代码:
    129. {{ $post->author->name }}
    130. 但是如果作者被删除,或者由于某种原因没有设置怎么办?你会得到一个错误,比如“非对象的属性”。
    131. 当然,您可以像这样阻止它:
    132. {{ $post->author->name ?? '' }}
    133. 但是你可以在 Eloquent 关系级别上做到这一点:
    134. public function author()
    135. {
    136. return $this->belongsTo('App\Author')->withDefault();
    137. }
    138. 在此示例中,如果没有作者附加到帖子,则author()关系将返回一个空模型。App\Author
    139. 此外,我们可以将默认属性值分配给该默认模型。
    140. public function author()
    141. {
    142. return $this->belongsTo('App\Author')->withDefault([
    143. 'name' => 'Guest Author'
    144. ]);
    145. }
    146. 11. Mutator 排序
    147. 想象一下你有这个:
    148. function getFullNameAttribute()
    149. {
    150. return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
    151. }
    152. 现在,您想按那个顺序订购full_name吗?这不起作用:
    153. $clients = Client::orderBy('full_name')->get(); // doesn't work
    154. 解决方案非常简单。我们需要在得到结果后对结果进行排序。
    155. $clients = Client::get()->sortBy('full_name'); // works!
    156. 请注意,函数名称不同——它不是orderBy,而是sortBy。
    157. 12. 全局范围内的默认排序
    158. 如果您想User::all()始终按name字段排序怎么办?您可以分配一个全局范围。让我们回到boot()上面已经提到的方法。
    159. protected static function boot()
    160. {
    161. parent::boot();
    162. // Order by name ASC
    163. static::addGlobalScope('order', function (Builder $builder) {
    164. $builder->orderBy('name', 'asc');
    165. });
    166. }
    167. 在此处阅读有关查询范围的更多信息。
    168. 13.原始查询方法
    169. 有时我们需要在 Eloquent 语句中添加原始查询。幸运的是,有一些功能。
    170. // whereRaw
    171. $orders = DB::table('orders')
    172. ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
    173. ->get();
    174. // havingRaw
    175. Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();
    176. // orderByRaw
    177. User::where('created_at', '>', '2016-01-01')
    178. ->orderByRaw('(updated_at - created_at) desc')
    179. ->get();
    180. 14. 复制:复制一行
    181. 短一个。没有深入的解释,这是制作数据库条目副本的最佳方法:
    182. $task = Tasks::find(1);
    183. $newTask = $task->replicate();
    184. $newTask->save();
    185. 15. 大表的 Chunk() 方法
    186. 与 Eloquent 不完全相关,它更多的是关于 Collection,但仍然很强大——要处理更大的数据集,你可以将它们分成几块。
    187. 代替:
    188. $users = User::all();
    189. foreach ($users as $user) {
    190. // ...
    191. 你可以做:
    192. User::chunk(100, function ($users) {
    193. foreach ($users as $user) {
    194. // ...
    195. }
    196. });
    197. 16. 创建模型时创建额外的东西
    198. 我们都知道这个 Artisan 命令:
    199. php artisan make:model Company
    200. 但是您知道生成模型相关文件的三个有用标志吗?
    201. php artisan make:model Company -mcr
    202. -m 将创建一个迁移文件
    203. -c 将创建一个控制器
    204. -r 表示控制器应该是足智多谋的
    205. 17. 保存时覆盖updated_at
    206. 你知道->save()方法可以接受参数吗?因此,我们可以告诉它“忽略”updated_at要填充当前时间戳的默认功能。看到这个:
    207. $product = Product::find($id);
    208. $product->updated_at = '2019-01-01 10:00:00';
    209. $product->save(['timestamps' => false]);
    210. updated_at在这里,我们用我们预定义的覆盖默认值。
    211. 18. update() 的结果是什么?
    212. 你有没有想过这段代码实际上返回了什么?
    213. $result = $products->whereNull('category_id')->update(['category_id' => 2]);
    214. 我的意思是,更新是在数据库中执行的,但它$result包含什么?
    215. 答案是受影响的行。因此,如果您需要检查有多少行受到影响,则无需调用任何其他方法 -update()方法将为您返回此数字。
    216. 19. 将括号转换为 Eloquent 查询
    217. 如果您在 SQL 查询中有和/或混合,会怎样,如下所示:
    218. ... WHERE (gender = 'Male' and age >= 18) or (gender = 'Female' and age >= 65)
    219. 如何将其翻译成 Eloquent?这是错误的方法:
    220. $q->where('gender', 'Male');
    221. $q->orWhere('age', '>=', 18);
    222. $q->where('gender', 'Female');
    223. $q->orWhere('age', '>=', 65);
    224. 顺序将不正确。正确的方法稍微复杂一些,使用闭包函数作为子查询:
    225. $q->where(function ($query) {
    226. $query->where('gender', 'Male')
    227. ->where('age', '>=', 18);
    228. })->orWhere(function($query) {
    229. $query->where('gender', 'Female')
    230. ->where('age', '>=', 65);
    231. })
    232. 20. orWhere 有多个参数
    233. 最后,您可以将一组参数传递给orWhere().
    234. “常规”方式:
    235. $q->where('a', 1);
    236. $q->orWhere('b', 2);
    237. $q->orWhere('c', 3);
    238. 你可以这样做:
    239. $q->where('a', 1);
    240. $q->orWhere(['b' => 2, 'c' => 3]);

    Eloquent ORM 似乎是一个简单的机制,但在底层,有很多半隐藏的功能和鲜为人知的方法来实现更多功能。在本文中,我将向您展示一些技巧。

    1. 递增和递减

    而不是这个:

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

    你可以这样做:

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

    这些也将起作用:

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

    2.异或法

    Eloquent 有很多功能结合了两种方法,比如“请做 X,否则做 Y”。

    示例 1 – findOrFail()

    代替:

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

    做这个:

    1 $user = User::findOrFail($id);

    示例 2 – firstOrCreate()

    代替:

    1 $user = User::where('email', $email)->first();
    2 if (!$user) {
    3 User::create([
    4 'email' => $email
    5 ]);
    6 }

    这样做:

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

    3.模型boot()方法

    在 Eloquent 模型中有一个神奇的地方boot()可以覆盖默认行为:

    1 class User extends Model
    2 {
    3 public static function boot()
    4 {
    5 parent::boot();
    6 static::updating(function($model)
    7 {
    8 // do some logging
    9 // override some property like $model->something = transform($something);
    10 });
    11 }
    12 }

    可能最流行的示例之一是在创建模型对象时设置一些字段值。假设您想在那一刻生成UUID 字段

    1 public static function boot()
    2 {
    3 parent::boot();
    4 self::creating(function ($model) {
    5 $model->uuid = (string)Uuid::generate();
    6 });
    7 }

    4. 与条件和顺序的关系

    这是定义关系的典型方式:

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

    但是您是否知道此时我们已经可以添加whereor orderBy?例如,如果您想要某种类型的用户的特定关系,也通过电子邮件订购,您可以这样做:

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

    5. 模型属性:时间戳、追加等。

    Eloquent 模型有一些“参数”,以该类的属性的形式。最受欢迎的可能是这些:

    1 class User extends Model {
    2 protected $table = 'users';
    3 protected $fillable = ['email', 'password']; // which fields can be filled with User::create()
    4 protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized
    5 protected $appends = ['field1', 'field2']; // additional values returned in JSON
    6 }

    但是等等,还有更多:

    1 protected $primaryKey = 'uuid'; // it doesn't have to be "id"
    2 public $incrementing = false; // and it doesn't even have to be auto-incrementing!
    3 protected $perPage = 25; // Yes, you can override pagination count PER MODEL (default 15)
    4 const CREATED_AT = 'created_at';
    5 const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden
    6 public $timestamps = false; // or even not used at all

    还有更多,我列出了最有趣的,更多请查看默认抽象模型类的代码并查看所有使用的特征。


    6.查找多个条目

    方法大家都知道find()吧?

    1 $user = User::find(1);

    我很惊讶很少有人知道它可以接受多个 ID 作为数组:

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

    7. 哪里X

    有一种优雅的方式来改变它:

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

    进入这个:

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

    是的,您可以更改任何字段的名称并将其作为后缀附加到“where”,它会神奇地起作用。

    此外,Eloquent 中有一些与日期/时间相关的预定义方法:

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

    8. 按关系排序

    一个更复杂的“技巧”。如果您有论坛主题但想通过最新帖子订购它们怎么办?论坛中很常见的要求,最后更新的主题在顶部,对吧?

    首先,为有关该主题的最新帖子描述一个单独的关系:

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

    然后,在我们的控制器中,我们可以做这个“魔术”:

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

    9. Eloquent::when()——不再有 if-else

    我们中的许多人使用“if-else”编写条件查询,如下所示:

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

    但是有一个更好的方法——使用when()

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

    它可能不会感觉更短或更优雅,但最强大的是传递参数:

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

    10. 属于默认模型

    假设您有属于 Author 的 Post 和 Blade 代码:

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

    但是如果作者被删除,或者由于某种原因没有设置怎么办?你会得到一个错误,比如“非对象的属性”。

    当然,您可以像这样阻止它:

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

    但是你可以在 Eloquent 关系级别上做到这一点:

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

    在此示例中,如果没有作者附加到帖子,则author()关系将返回一个空模型。App\Author

    此外,我们可以将默认属性值分配给该默认模型。

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

    11. Mutator 排序

    想象一下你有这个:

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

    现在,您想按那个顺序订购full_name吗?这不起作用:

    1 $clients = Client::orderBy('full_name')->get(); // doesn't work

    解决方案非常简单。我们需要在得到结果后对结果进行排序。

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

    请注意,函数名称不同——它不是orderBy,而是sortBy。


    12. 全局范围内的默认排序

    如果您想User::all()始终按name字段排序怎么办?您可以分配一个全局范围。让我们回到boot()上面已经提到的方法。

    1 protected static function boot()
    2 {
    3 parent::boot();
    4
    5 // Order by name ASC
    6 static::addGlobalScope('order', function (Builder $builder) {
    7 $builder->orderBy('name', 'asc');
    8 });
    9 }

    在此处阅读有关查询范围的更多信息。


    13.原始查询方法

    有时我们需要在 Eloquent 语句中添加原始查询。幸运的是,有一些功能。

    1 // whereRaw
    2 $orders = DB::table('orders')
    3 ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
    4 ->get();
    5
    6 // havingRaw
    7 Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();
    8
    9 // orderByRaw
    10 User::where('created_at', '>', '2016-01-01')
    11 ->orderByRaw('(updated_at - created_at) desc')
    12 ->get();

    14. 复制:复制一行

    短一个。没有深入的解释,这是制作数据库条目副本的最佳方法:

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

    15. 大表的 Chunk() 方法

    与 Eloquent 不完全相关,它更多的是关于 Collection,但仍然很强大——要处理更大的数据集,你可以将它们分成几块。

    代替:

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

    你可以做:

    1 User::chunk(100, function ($users) {
    2 foreach ($users as $user) {
    3 // ...
    4 }
    5 });

    16. 创建模型时创建额外的东西

    我们都知道这个 Artisan 命令:

    1 php artisan make:model Company

    但是您知道生成模型相关文件的三个有用标志吗?

    1 php artisan make:model Company -mcr
    • -m 将创建一个迁移文件
    • -c 将创建一个控制器
    • -r 表示控制器应该是足智多谋的

    17. 保存时覆盖updated_at

    你知道->save()方法可以接受参数吗?因此,我们可以告诉它“忽略”updated_at要填充当前时间戳的默认功能。看到这个:

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

    updated_at在这里,我们用我们预定义的覆盖默认值。


    18. update() 的结果是什么?

    你有没有想过这段代码实际上返回了什么?

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

    我的意思是,更新是在数据库中执行的,但它$result包含什么?

    答案是受影响的行。因此,如果您需要检查有多少行受到影响,则无需调用任何其他方法 -update()方法将为您返回此数字。


    19. 将括号转换为 Eloquent 查询

    如果您在 SQL 查询中有和/或混合,会怎样,如下所示:

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

    如何将其翻译成 Eloquent?这是错误的方法:

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

    顺序将不正确。正确的方法稍微复杂一些,使用闭包函数作为子查询:

    1 $q->where(function ($query) {
    2 $query->where('gender', 'Male')
    3 ->where('age', '>=', 18);
    4 })->orWhere(function($query) {
    5 $query->where('gender', 'Female')
    6 ->where('age', '>=', 65);
    7 })

    20. orWhere 有多个参数

    最后,您可以将一组参数传递给orWhere().“常规”方式:

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

    你可以这样做:

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

  • 相关阅读:
    详解设计模式:策略模式
    【数据结构】线性表的应用:稀疏一元多项式运算器
    5.k8s jenkins集成k8s一键发布案例
    Minitab Express for Mac(数据分析软件)附破解补丁 v1.5.0 支持M1
    学习笔记-php代理审计_可能被利用的函数
    【Python百日进阶-Web开发-Feffery】Day400 -“一起Dash”训练营Lesson-09_利用多页面应用_课堂
    基于Struts2+Hibernate开发社区蔬菜、食品交易平台
    Qt实战案例(58)——利用QObject类实现定时器功能
    微信小程序怎么通过图片链接获取图片宽高比(适合在下载图片前获取宽高比)
    HDMI之EDID
  • 原文地址:https://blog.csdn.net/zh7314/article/details/125554094