提高 Laravel Eloquent 查询的5个小技巧
翻译自:aschmelyun.com/blog/5-tips-for-sup...
在过去的五年左右的时间里,我一直在与Laravel合作,在那段时间里,我遇到了一些案例,在这些案例中,我需要一种独特或非典型的方式来从应用程序中返回数据。使用Eloquent
提取数据变得容易,但是仍然有一些用例需要我进行一些挖掘和理解,以弄清楚如何做自己想完成的事情。
我在下面列出了其中的五个,以及代码示例和为每个示例返回的伪数据。
准备好? 让我们开始吧!
有条件地建立查询
假设我们有一个 Property 模型,其中包含 价格列以及是否允许您养宠物。当用户访问时,我们希望过滤掉数据example.com/properties?rent=1200&pets=true
。
public function test(Request $request)
{
if ($request->get('rent') && $request->get('pets')) {
return Property::where('rent', <=, $request->get('rent'))->where('pets_allowed', true))->get();
}
if ($request->get('rent')) {
return Property::where('rent', <=, $request->get('rent'))->get();
}
if ($request->get('pets')) {
return Property::where('pets_allowed', true))->get();
}
return Property::all();
}
我们可以建立一个查询,然后根据这些条件(而不是依赖它们)添加到查询中。
使用Model::query()
,然后我们可以根据存在的过滤器链接到 where
语句上。
最后调用get
返回我们的数据:
public function test(Request $request)
{
$properties = Property::query();
if ($request->get('rent')) {
$properties->where('rent', <=, $request->get('rent'));
}
if ($request->get('pets')) {
$properties->where('pets_allowed', true));
}
return $properties->get();
}
这样可以确保每个过滤器仅需要一个条件语句,并且可以将过滤器组合自动链接到此查询。
返回最新关系
以我们之前的 Property 模型为例,假设有多个与 Tenant 模型相关联的 租户 模型。要拉入所有带有其附加租户的属性,您可能会使用类似以下内容的方法:
public function test(Request $request)
{
return Property::with('tenants')->get();
}
但是,如果您只想返回一位租户,该怎么办?
public function tenants()
{
return $this->hasMany(Tenant::class);
}
public function newestTenant()
{
return $this->hasOne(Tenant::class)->orderBy('lease_expires_at', 'desc');
}
现在,如果我们回到以前的测试方法并将其修改为用 Property::with('newestTenant')
,我们将只得到一个租户。
按嵌套值过滤项目
使用我们之前的财产和租户模型以及关系,如果只想返回那些租户没有狗或猫的财产,该怎么办?您可能可以使用类似以下的内容:
public function test(Request $request)
{
return Property::with(['tenants' => function($query) {
$query->where('has_dogs', false)->where('has_cats', false);
}])->get();
}
但我想做的是过滤掉这些属性,然后只返回那些包含那些过滤后的关系的属性。我们可以在对象上运行一个foreach循环并检查该空的租户数组,或者可以使用Eloquent的whereHas()
方法:
public function test(Request $request) {
return Property::whereHas('tenants', function($query) {
$query->where('has_dogs', false)->where('has_cats', false);
})->with(['tenants' => function($query) {
$query->where('has_dogs', false)->where('has_cats', false);
}])->get();
}
通过使用whereHas()
,上面的方法仅返回与作为第一个参数输入的列匹配的那些属性。我们的第二个参数基于链接到查询对象的方法过滤该列。
然后,我们通过将这些租户附加到返回的属性中来进行后续操作,并获得结果。
生成和插入动态属性
我们假设有两个新模型:Technicians和Requests。技术人员与其他技术人员共享多个请求。如果我们希望有一种方法可以一眼就能轻松地看到我们的数据,那么每个技术人员对象有多少个请求呢?我们可以将它们每个都作为延迟加载包含进来,然后获取数组的长度,或者我们可以创建一个动态属性来计算并保存该值。
首先,我们必须在Technician模型添加以下方法:
public function getRequestsCountAttribute()
{
return $this->requests()->count();
}
在Laravel中,动态属性的命名约定:
- 使用camelCase
- 以
get
开始 - 包含您想要的下一个列名称
- 结束于
Attribute
因此,以上方法将在我们返回的技术人员上创建一个动态列,称为requests_count
,该列将包含附加至模型的已连接请求的数量。
轻松过滤日期
关于第五个也是最后一个技巧,让我们回到租户模型。正如我们前面提到的,每个人的租约到期时都有一列要保存。好吧,如果我们只想返回那些在2021年7月到期的用户,该怎么办?
我们也许可以做类似的事情:
public function test(Request $request)
{
return Tenant::where('lease_expires_at', 'LIKE', '2021-07-%')->get();
}
那将完美地工作,并且只返回我们想要的租户。但是我并不热衷于LIKE
在不需要的地方使用语句。它们可能会变得凌乱,Laravel为我们提供了两种更好的方法:
public function test(Request $request)
{
return Tenant::whereMonth('lease_expires_at', '07')->whereYear('lease_expires_at', '2021)->get();
}
使用whereMonth
和whereYear
,我们只能过滤那些租约在2021年7月到期的模型。如果我们想提供一些动态过滤功能,我们甚至可以将那些硬编码的值替换为,$request->get('month')
或者$request->get('year')
则可以替换。
目前为止就这样了!
这是五个简单但功能强大的方法和组织技巧,可用于Laravel的Eloquent ORM来提高生产力。此外,这可能有助于您开始思考如何优化查询并减少整体代码混乱。
本作品采用《CC 协议》,转载必须注明作者和本文链接
第一条可以用 when 来解决吧