Laravel 中如何区别 Model 或者是 Builder?
User::where('id',1)->update([])
和 User::find(1)->update([])
有异曲同工之效.
额?
当你通过 Laravel 与数据库交互时,你可能时而用 Eloquent,时而用更接近于 SQL 原生的查询构造器。
Eloquent 其实就是对查询构造器的对象化包装。就像是给查询器外面包了一层语法糖 :)。
底层机制.
一般情况下,所有关于查询构造器的内容都可以在这个命名空间下找到: Illuminate\Database\Query\Builder
而所有关于 Eloquent 的内容都会放在这个命名空间下:
Illuminate\Database\Eloquent\Model
深入 Eloquent
会了不难 :)
Eloquent 也是由很多部分组成的,最具有魅力的部分莫过于 Model 类、它自身用的查询构造器,还有一些比较重要的类,像模型关联等。
举个栗子,我们现在就来具体剖析一下两种查询语句
User::where('id',1)
: 这条语句是从一个 eloquent 模型开始,当调用 where() 函数时会返回 eloquent 构造器的实例,也就是说你后面还可以继续调用很多查询方法。注意:Eloquent 构造器是继承自查询构造器的。
User::find(1)
: 这条语句会直接返回主键为1的数据的对象。注意:如果是同时查询多条数据记录,就会返回一个 eloquent 集合,比如:find([1,2,3])
所以第一种用 where() 方法的查询语句会返回 eloquent 构造器的实例,也就是说我们可以在此基础上继续调用其他的查询方法,而且除了 eloquent 构造器的方法外,还可以调用查询构造器的方法,比如 join
方法。
而对于第二个查询语句,因为返回的是对象,我们既可以直接使用对象的属性,也可以继续调用其他查询方法。
注意:构造器和 eloquent 有一些共同的方法。
Eloquent 会首先去调用自身的方法,如果找不到,就会去调用查询构造器的方法。这种机制有点像继承时子类对方法的重写(译者注:正如前面提到的,eloquent 构造器就是继承于查询构造器的)。这里是通过魔术方法 __call 实现的https://github.com/laravel/framework/blob/....
update 方法就是这样一个二者都有的方法。
然而,虽然同是 update 方法,执行过程还是有很多不同的,比如使用 eloquent 更新数据的时候,如果数据不存在,会返回 false, 而且有一些可选参数,比如开发者可以选择是否设置时间戳。
为什么要了解这些?
并不是说你一定要这样做,但是在某些情况下,你可能会需要重写 update 方法。比如前面提到的这条语句 User::find(1)->update([...])
, 由于 User::find(1)
返回的是对象,在对象上直接调用 update 方法, 就会执行你重写的方法。
但是,如果返回的不是对象,而是构造器 ( builder ),那么你写的方法就不会被执行了,这种情况会默认执行构造器的方法。
我们当然都希望可以通过其他途径解决所遇到的问题,而不是重写方法。
而我写这篇文章的目的就是想强调 “知其所以然” 的重要性 :)
参考文献
-
laravel/framework/blob/5.7/src/Illuminate/Database/Eloquent/Builder.php
-
laravel/framework/blob/5.7/src/Illuminate/Database/Eloquent/Model.php
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
“With the second query, we can append both model and query builder methods still.” 这句话理解不到位,不知道翻译的对不对,求指正,多谢
@rachel 按照上下文来讲,翻译的挺好的
@Summer Thanks a lot :star2:
但是,现实的情况是你写的方法不会被执行,因为默认是执行 eloquent 构造器自身的方法的。
这句话如何理解,有大佬知道吗@等车的猪 我的错,翻译不准确,已经修改了。总结就是如果是在对象上调用 update 方法,重写的方法就可以被执行,如果是在 query builder 上调用,重写的方法就不会执行。(因为轮不到 :joy:)
由于自己一知半解,导致错误,感谢提醒,让我真正做到 “知其所以然” :star2:
附原文:
as long as you have a Model instance say like in our example above User::find(1)->update([...]your overridden method will be executed.
But in the case, the other kind of query is used where a Builder is returned, your method will not run as the default update within the Builder will be called instead.