美文网首页
3分钟短文:Laravel模型作用域,为你“节省”更多代码

3分钟短文:Laravel模型作用域,为你“节省”更多代码

作者: 程序员小助手 | 来源:发表于2020-10-23 20:33 被阅读0次

引言

原则上代码写一次,处处是引用,不需要大量的冗余代码,这是一种趋势,也是提高代码健壮性的努力方向。
laravel模型为我们提供了一层数据库操作层,将数据交互独立出来。

但是久而久之,随着项目的需求不断扩大,最常用的查询操作,同样会有大量的冗余代码。

img

本文就来讲讲,连模型的自我瘦身,缩减模型的代码。

全局作用域

假设有些数据库查询操作,无论是在控制器内,或者在模板文件内,或者命令行方法内,都有重复的使用需求,要是在模型内有一个公用的方法,默认就加上这些筛选条件,就可以显著减少代码量了。

比如有一个查询条件:

$publishedEvents = Event::where('published', '=', 1)->get();

上述代码最后生成的SQL语句如下:

SELECT * FROM events WHERE `published` = 1;

如果条件 published = 1 在默认的情况下需要开启,我们可以使用laravel模型的 全局作用域 方式为所有查询追加上这个条件。

在模型文件 Event 内头部引入下述类:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

在模型类内部,手动实现 boot 方法:

protected static function boot()
{
    parent::boot();
    static::addGlobalScope('published', function (Builder $builder) {
        $builder->where('published', '=', 1);
    });
}

这样SQL语句 where published = 1 就会追加到所有的模型查询方法内,只要是创建生成了 QueryBuilder 对象的,都会附加上此约束语句。

那有些读者可能要问了:“如果我不想要这个约束语句,岂不是连模型也永不了了?

那哪儿能呢!不过就是QueryBuilder的一个属性数组的一个元素而已,手动移除就行了,这样特例问题就解决了。

$events = Event::withoutGlobalScopes()->get();

看到了吧,追加上很简单,移除更简单。

本地作用域

接上一节的 withoutGlobalScope 要每次手动屏蔽的方式不同,有时候使用有局限的作用域更能解决问题。所以,本地作用域 应运而生,专门用于某个模型文件的方法,手动调用的时候就起作用,不调用就不会主动追加。

而声明一个本地作用域,只要遵循laravel的语法规定即可,如下示例:

public function scopePublished($query)
{
    return $query->where('published', 1);
}

只需要声明一个以 scope 为首的小驼峰命名的函数方法即可,并返回一个 QueryBuilder 对象实例。调用的时候要手动追加上:

$events = Event::published()->get();

其中 published()方法就是映射到 scopePublished 方法。

上面的演示代码,没有接收用户输入,下面演示一下带参的传递方式。比如有这样一个查询需求:

$events = Event::where('zip', $zipCode)->get();

使用本地作用域实现出来:

public function scopeZip($query, $zip)
{
    return $query->where('zip', $zip);
}

按照位置传入即可。使用的使用,直接传入:

$zip = '43016';
$events = Event::zip($zip)->get();

这样就完成了本地作用域的使用,是不是很直观。

既然本地作用域返回的是 QueryBuilder 实例,那么自然就可以链式调用本地作用域的方法,和 QueryBuilder 的方法。我们再声明一个本地作用域方法:

public function scopeAttendees($query, $maximum)
{
    return $query->where('max_attendees', $maximum);
}

现在把上述两个方法串联使用:

$events = Event::zip(43016)->attendees(2)->get();

生成的SQL语句也符合预期:

SELECT * FROM events WHERE zip = '43016' and max_attendees = '2';

写在最后

本期我们又旧事重提,把laravel模型的作用域设计方法拿出来温习了一下。讲述了两个方法:

  • 全局作用域:全局起作用,需要手动移除;

  • 本地作用域:只有手动调用起作用,可链式使用;

这样的设计模式可以很大程度上节约查询代码,但是对于维护,需要同等熟悉的开发者彼此遵循开发规范,写出可维护的代码。

Happy coding :-)

我是@程序员小助手,专注编程知识,圈子动态的IT领域原创作者

🏆 掘金技术征文|双节特别篇

相关文章

  • 3分钟短文:Laravel模型作用域,为你“节省”更多代码

    引言 原则上代码写一次,处处是引用,不需要大量的冗余代码,这是一种趋势,也是提高代码健壮性的努力方向。larave...

  • Laravel 模型使用scope前缀的方法

    Laravel中模型中可以定义scope开头方法,这类方法可以模型直接使用。这类方法也称作查询作用域 例子: 现有...

  • 作用域&js分号的作用

    以上代码输出为: 原因:作用域:执行上下文中包含作用域链在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行...

  • let - 学习笔记

    一、let声明的变量,仅在代码块内有效 下述代码中i为var声明,为全局作用域 下列代码中let仅在块状作用域内有...

  • C语言基础掌握之day5

    内存管理 作用域 一个C语言变量的作用域可以是代码块作用域,函数作用域或者文件作用域。代码块是{}之间的一段代码。...

  • 作用域、二义性和extern

    一个C语言变量的作用域可以是代码块 作用域,函数作用域或者文件作用域。代码块是{}之间的一段代码。 总结

  • 高级篇 Laravel-EloquentORM

    欢迎大家关注我的其他 CSDN博客 和 简书 ,互相交流! 查询作用域# 全局作用域# 全局作用域允许你对给定模型...

  • 词法作用域&动态作用域

    词法作用域(静态作用域) 词法作用域也叫静态作用域,jsvascript为词法作用域。词法作用域关心的是你的函数申...

  • 【C语言】内存管理-008

    第八章 内存管理 8.1 作用域 C语言变量的作用域分为: 代码块作用域(代码块是{}之间的一段代码) 函数作用域...

  • 作用域和闭包

    作用域链 (据我所知)所有的编程语言都存在作用域链。整个代码存在全局作用域、函数作用以及块级作用域。 上述代码将会...

网友评论

      本文标题:3分钟短文:Laravel模型作用域,为你“节省”更多代码

      本文链接:https://www.haomeiwen.com/subject/ryetmktx.html