首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

重构whereHas以通过Laravel中的全局作用域使用

在 Laravel 中,whereHas 方法用于在关联模型上添加查询条件。全局作用域(Global Scopes)则是一种在模型上定义全局约束的方式,这些约束会自动应用于模型的所有查询。将 whereHas 与全局作用域结合使用,可以在多个地方重用相同的查询逻辑,从而提高代码的可维护性和可读性。

基础概念

  1. 全局作用域:全局作用域是一个在模型类中定义的静态方法,它接收一个查询构建器实例,并返回修改后的查询构建器实例。全局作用域会自动应用于模型的所有查询。
  2. whereHaswhereHas 方法用于在关联模型上添加查询条件。它允许你在主模型上定义条件,以过滤与其关联的子模型。

相关优势

  • 代码重用:通过全局作用域,可以在多个地方重用相同的查询逻辑,减少重复代码。
  • 可维护性:将查询逻辑封装在全局作用域中,使得代码更加模块化和易于维护。
  • 可读性:全局作用域提供了一种清晰的方式来组织和理解模型的查询逻辑。

类型与应用场景

  • 单一全局作用域:适用于在整个应用中都需要应用的简单查询约束。
  • 复合全局作用域:通过 Scope 类的组合,可以创建更复杂的全局作用域,以满足更复杂的查询需求。

示例代码

假设我们有一个 Post 模型和一个 User 模型,它们之间存在一对多的关系。我们希望在查询帖子时,只获取那些作者活跃的用户发布的帖子。

首先,在 User 模型中定义一个全局作用域:

代码语言:txt
复制
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class User extends Model
{
    // ...

    public static function boot()
    {
        parent::boot();

        static::addGlobalScope(new ActiveUserScope);
    }
}

class ActiveUserScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('is_active', 1);
    }
}

然后,在 Post 模型中使用 whereHas 方法结合全局作用域:

代码语言:txt
复制
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // ...

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function scopeActiveUserPosts($query)
    {
        return $query->whereHas('user');
    }
}

最后,在控制器中使用这个作用域:

代码语言:txt
复制
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::activeUserPosts()->get();

        return view('posts.index', compact('posts'));
    }
}

遇到的问题及解决方法

如果在重构 whereHas 以通过全局作用域使用时遇到问题,可能是由于以下原因:

  1. 全局作用域未正确注册:确保在模型中正确调用了 addGlobalScope 方法,并且全局作用域类实现了 Scope 接口。
  2. 作用域逻辑错误:检查全局作用域中的 apply 方法,确保它正确地修改了查询构建器实例。
  3. 关联关系配置错误:确保在模型中正确配置了关联关系,并且关联关系的名称与 whereHas 方法中的参数一致。

参考链接

通过以上步骤和示例代码,你应该能够成功地将 whereHas 与全局作用域结合使用,从而提高代码的可维护性和可读性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

样式的作用域──页面重构中的模块化设计(一)

样式的作用域──页面重构中的模块化设计(一) 由 Ghostzhang 发表于 2010-03-24 18:41 很久没有更新blog了,这段时间实在是发生了很多的事,累身累心。...写过程序的同学应该都知道,变量是有作用域的(不知道的同学自己去问谷歌,这里就不作解释了),样式的定义也同样存在着作用域的问题,即定义的作用范围,很容易就能理解,如下面的p的作用域: /*作用域:全局*/...再来说说“作用域”,相信大家很容易就会想到“全局”、“公共”这些词,关注过模块化的同学应该都知道,网上说得最多的一种“模块化”,就是像header、footer这样的以大区域划分。...最后几点要特别注意的: 除了标签选择器之外,哪些类是使用于公共级、栏目级中的,如.tx_hit{color:#FF0000 !important;}的适用范围是公共级的,应该放于全局的定义中。...标签选择器一般属于栏目定义,有时会用于公共级作用域中,除了最基础的reset之外,应尽可能少使用在公共级定义中 可继承的属性定义使用时须注意影响的范围,特别是在标签选择器中使用时 同类选择器无加权 接下来的内容就是以这个为基础的

37040

栏目级作用域──页面重构中的模块化设计(二)

栏目级作用域──页面重构中的模块化设计(二) 由 Ghostzhang 发表于 2010-04-03 14:49 在《样式的作用域──页面重构中的模块化设计(一)》中,我将样式的作用域分为了三个部分...简单解释下栏目级(局部公共)和页面级: 页面级可分为两种情况:在多个页面间,页面级作用域指针对某一单独的页面定义;在同一个页面中,页面级作用指针对某一标签的定义。它将决定最终的页面效果。...栏目级(局部公共)介于全局与单个页面之间的一个作用域,影响一个栏目(或某区域)。通常以某一类选择符做为开始,以包含选择符的方式将样式定义限定在某一区域中。...需要消化下的内容,决定一个样式定义是属于哪个作用域的因素有以下两点: 样式定义所在样式文件中的位置。(同样的一个定义,放在不同的位置,所影响的范围会有所不同。)...另外需要在思维上注意的一点,以作用域划分,并不意味着有着对应的文件,可能有些同学会习惯的以为一个作用域就应该对应着一个文件。

34930
  • Dockerfile 中 ARG 的使用与其作用域(scope)探究

    使用 ARG 可以有效的复用 Dockerfile。每次镜像更新,只需要动态的在 build 命令中传入新的参数值即可。...0x01 结论 在第一个 FROM 之前的所有 ARG , 在所有 FROM 中生效, 仅在 FROM 中生效 在 FROM 后的 ARG, 仅在当前 FROM 作用域生效。...即尽在当前 阶段 (stage) 生效 对照组解析 在随后的 Dockerfile 中, 只定义了一个变量 image , 并在 FROM 和 stage 中重复使用 对照组1: stage1 和 stage11...均在 FROM 中使用了变量 $image: **作用域在所有 FROM 中 成功拉取 FROM $image 并完成 layer 构建 但是在 RUN 中无法正确输出结果,即 image 的值 alpine...:3.12 对照组2: stage1 vs stage2: 作用域在 FROM stage 内部 在 stage2 的作用域中声明了 ARG image,且能正确输出结果。

    64420

    Vue style里面使用@import引入外部css, 作用域是全局的解决方案

    问题描述 使用@import引入外部css,作用域却是全局的 export default { name...background-color: #3982e5; } Add “scoped” attribute to limit CSS to this component only 这句话大家应该是见多了, 我也使用...scoped, 但是使用@import引入外部样式表作用域依然是全局的,看了一遍@import的规则后, 进行初步猜测,难道是@import引入外部样式表错过了scoped style?...又回想到此前看过的前端性能优化文章里面都有提到,在生产环境中不要使用@import引入css,因为在请求到的css中含有@import引入css的话,会发起请求把@import的css引进来,多次请求浪费不必要的资源.../static/css/user.css"; 我们只需把@import改成引入外部样式,就可以解决样式是全局的问题 <style scoped

    98310

    如何使用Vue中的嵌套插槽(包括作用域插槽)

    作者:Michael Thiessen 译者:前端小智 来源:medium 最近我弄清楚了如何递归地实现嵌套插槽,包括如何使用作用域插槽来实现。...看到这里,你或许就可以明白了,我们可以使用此概念并将其应用于我们的组件。 相反,我们将递归嵌套组件以表示列表。 我们最终将渲染出这样的内容。...因此,我们将从“Parent”中获取该内容,然后将其渲染到“Grandchild”插槽中。 添加作用域插槽 与嵌套作用域插槽唯一不同的是,我们还必须传递作用域数据。...如果没有提供插槽,则默认元素内部的内容,并像以前一样渲染list[0]。 但是如果我们提供了一个slot,它会将其渲染出来,并通过slot作用域将列表项传递给父组件。...这里的递归情况类似。 如果我们将插槽传递给v-for,它将在下一个v-for的插槽中进行渲染,因此我们得到了嵌套。 它还从作用域槽中获取item并将其传递回链。

    5K30

    Vue style里面使用@import引入外部css, 作用域是全局的解决方案

    问题描述 使用@import引入外部css,作用域却是全局的 export default { name...background-color: #3982e5; } Add “scoped” attribute to limit CSS to this component only 这句话大家应该是见多了, 我也使用...scoped, 但是使用@import引入外部样式表作用域依然是全局的,看了一遍@import的规则后, 进行初步猜测,难道是@import引入外部样式表错过了scoped style?...又回想到此前看过的前端性能优化文章里面都有提到,在生产环境中不要使用@import引入css,因为在请求到的css中含有@import引入css的话,会发起请求把@import的css引进来,多次请求浪费不必要的资源.../static/css/user.css"; 我们只需把@import改成引入外部样式,就可以解决样式是全局的问题 <style scoped

    1.4K30

    精:理解和使用 .NET Core中依赖注入的作用域

    理解作用域的工作原理可以帮助你更高效地管理资源,避免常见的陷阱,如内存泄漏和不必要的对象创建。本文将探讨什么是作用域、.NET Core 中可用的不同作用域类型,以及如何通过实际示例使用它们。...Singleton(单例): 在整个应用程序的生命周期中共享一个服务实例。 在 .NET Core 中使用作用域 让我们深入了解如何通过示例使用这些作用域。 1....Scoped(作用域) 作用域服务在每个请求中只创建一次。这对在单个请求中需要保持状态的服务非常有用。...总结 在 .NET Core 中理解并使用合适的服务作用域对资源管理和应用性能至关重要。...通过慎重选择合适的作用域,你可以优化应用程序的性能和可维护性。 希望这篇文章能帮助你理解 .NET Core 中的作用域概念及其有效的使用方法。如果你有任何疑问,请留言讨论!

    13410

    Laravel Eloquent 模型关联关系(下)

    在前面两篇教程中,学院君陆续给大家介绍了 Eloquent 模型类支持的七种关联关系,通过底层提供的关联方法,我们可以快速实现模型间的关联,并且进行关联查询。...另外,如果访问的是模型实例上的 author() 方法时,返回的不是用户实例了,而是一个关联关系实例,该实例注入了查询构建器,所以你可以在其基础上通过方法链的方式构建查询构建器进行更加复杂的查询,我们以一个一对多的查询为例...whereHas/orWhereHas 方法基于闭包函数定义查询条件,比如我们想要过滤发布文章标题中包含「Laravel学院」的所有用户: $users = User::whereHas('posts...: 如果你想进一步过滤出文章标题和评论都包含「Laravel学院」的用户,可以在上述闭包函数中通过查询构建器进一步指定: $users = User::whereHas('posts', function...whereHas 方法和 orWhereHas 方法相对的,也有 whereDoesntHave 和 orWhereDoesntHave 方法,使用方法一样,这里就不再赘述了。

    19.6K30

    Laravel学习记录--Model

    Laravel 自带的 软删除功能 就利用全局作用域从数据库中提取「未删除」的模型。编写自定义的全局作用域可以提供一个方便、简单的方法来确保给定模型的每个查询都受到一定的约束。...要将全局作用域分配给模型,需要重写给定模型的 boot 方法并使用 addGlobalScope 方法: 全局作用域 删除一个全局作用域 User::withoutGlobalScope(AgeScope::class)->get(); 删除多个全局作用域 如果你想要删除几个甚至全部的全局作用域,可以使用...Laravel中Eloquent还支持动态作用域,动态作用域指在查询过程中动态设置预置过滤器的查询条件,动态作用域与本地作用域类似,都是以scope作为前缀,调用方法也相同,不同的是动态作用域可以通过额外参数指定查询条件...','>',$price) } 在查询时直接调用 $goods = Good::Price(200)->get(); 全局作用域可理解为限制约束,本地作用域/动态作用域则可理解为一些定义好的常用约束集合

    13.6K20

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

    全局作用域 假设有些数据库查询操作,无论是在控制器内,或者在模板文件内,或者命令行方法内,都有重复的使用需求,要是在模型内有一个公用的方法,默认就加上这些筛选条件,就可以显著减少代码量了。...events WHERE `published` = 1; 如果条件 published = 1 在默认的情况下需要开启,我们可以使用laravel模型的 全局作用域 方式为所有查询追加上这个条件。...本地作用域 接上一节的 withoutGlobalScope 要每次手动屏蔽的方式不同,有时候使用有局限的作用域更能解决问题。...使用的使用,直接传入: $zip = '43016'; $events = Event::zip($zip)->get(); 这样就完成了本地作用域的使用,是不是很直观。...讲述了两个方法: 全局作用域:全局起作用,需要手动移除; 本地作用域:只有手动调用起作用,可链式使用; 这样的设计模式可以很大程度上节约查询代码,但是对于维护,需要同等熟悉的开发者彼此遵循开发规范,写出可维护的代码

    1.4K22

    3分钟短文 | Laravel复杂SQL超多WHERE子句,本地作用域你没用过

    就拿这个 model 的查询说起,你可以 "查询作用域”这么个时髦的功能,有效分散和重用查询条件。 拿“全局作用域”来说,它可以给模型的查询都添加上约束。...Laravel 的软删除功能就是利用此特性从数据库中获取 “未删除”的模型。 你可以编写你自己的全局作用域,很简单、方便的为每个模型查询都加上约束条件。看官方给出的示例: ?...要将全局作用域分配给模型,需要重写模型的 booted 方法并使用 addGlobalScope 方法: ?...SQL 学习了全局作用域,那么本地作用域就更好理解了。...就是在对应的 Eloquent 模型方法前添加 scope 前缀,在模型中构造如下的作用域方法: ?

    2.8K10

    3分钟短文:Laravel 从软删除说到模型作用域的概念

    我们从软删除的使用,再顺便说一说模型内的作用域的概念。 代码时间 常规的删除操作分两步进行,一步是把数据从数据库中查询出来,使用laravel模型的方法, 则返回的是一个模型对象。...然后在模型中,引入软删除的功能,将其进行全局生效的使用。...格式} 通过追寻源代码,我们注意到 SoftDeletes 其实是注册了一个模型内的全局作用域方法: public static function bootSoftDeletes(){ static...如果是想软删除条目那样,默认把所有的查询都追加 自定义的查询条件,就需要我们上面说的全局作用域了。...写在最后 本文从laravel模型的写操作删除动作,讲到了软删除的概念。进而引申出来本地作用域和全局作用域的使用。软删除几乎贯穿了我们应用的始终,需要大家勤学苦练。

    1.4K30

    【半译】在ASP.NET Core中创建内部使用作用域服务的Quartz.NET宿主服务

    在我的上一篇文章中,我展示了如何使用ASP.NET Core创建Quartz.NET托管服务并使用它来按计划运行后台任务。...作业可以直接使用作用域服务 由于作业实例是从IServiceProvder作用域中解析来的,因此您可以在作业实现的构造函数中安全地使用作用域服务。...可替代解决方案 我喜欢本文中显示的方法(使用中间QuartzJobRunner类),主要有两个原因: 您的其他IJob实现不需要任何有关创建作用域的基础结构的知识,只需完成标准构造函数注入即可 在IJobFactory...该QuartzJobRunner通过创建和处理作用域隐式地处理这个问题。 但是,此处显示的方法并不是在工作中使用范围服务的唯一方法。...该运行程序负责创建一个DI范围,实例化请求的作业并执行它,因此最终IJob实现可以在其构造函数中使用作用域中的服务。

    1.9K10

    在以 CentOS7.6 为基础镜像的 Docker 容器中通过 NFS 将内存挂载成高速硬盘使用

    CentOS7.6 为基础镜像的 Docker 容器中通过 NFS 将内存挂载成高速硬盘使用 文章目录 在以 CentOS7.6 为基础镜像的 Docker 容器中通过 NFS 将内存挂载成高速硬盘使用...通过对问题的分析,我采取了以下解决方案: 通过把内存挂载成硬盘,可以大幅度提高磁盘的性能; 由于不能在同一个容器内进行读写,可以使用 NFS 来解决; 允许使用特权模式,可以在容器内部挂载磁盘...适用范围狭窄; 不能通过 systemd 来管理服务; 生产环境中不推荐使用此方案。...4.2.2 Docker 容器的互联 在同一台主机的未指定网络方案的情况下,Docker 是通过 bridge 的方式进行桥接的。如果涉及到跨主机的互联,那么可能需要使用其他方案。...4.2.3 在容器中的其他 NFS 解决方案 nfs-ganesha 也是 NFS 在容器中的一个比较流行的解决方案。

    2.2K30

    在 Laravel Eloquent 模型类中使用作用域进行查询

    以 User 模型类为例,我们在系统中可能只想针对已经验证过邮箱的用户进行操作,在没有介绍「作用域」之前,可能你会在应用中到处编写这样的代码: $users = User::whereNotNull('...这样,当我们通过 User 模型类进行查询的时候,就会自动应用全局作用域指定的查询条件了,以 User::all() 为例,我们通过 Telescope 的 「Queries」 页面就能看到对应的 SQL...通过匿名函数实现 如果你觉得编写一个「全局作用域」类很麻烦,过滤逻辑又很简单,还可以在模型类的 boot 方法中通过匿名函数实现全局作用域: protected static function boot...,不同场景需要不同的预置过滤器,这个时候就不能使用「全局作用域」了,要改用「局部作用域」,在不同场景应用不同的局部作用域来完成查询功能。...动态作用域 此外,Eloquent 模型类还支持「动态作用域」,所谓动态作用域指的是在查询过程中动态设置预置过滤器的查询条件,动态作用域和局部作用域类似,过滤器方法名同样以 scope 开头,只不过可以通过额外参数指定查询条件

    2.5K20

    前端关键技术点杂烩,这些你必须知道

    父函数定义的变量在子函数的作用域链中,子函数没有被销毁,其作用域链中所有变量和函数就会被维护,不会被销毁。...20、JS 作用域链 在一些类 C 的语言中有“块级作用域”,即花括号的每一段代码都有自己的独立作用域,而 JS 只有函数级作用域;JS 作用域链的第一个对象始终是当前执行代码所在环境的变量对象(VO)...,声明函数在全局作用域,此时作用域链只有一个环境对象;运行函数时作用域链顶端加入了函数内的环境对象,运行完毕时顶端环境对象被销毁,以此类推。...JS 在查找变量时会从链的顶端(就近原则)一直向下查找。如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。...全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。 (最好和闭包一起理解) 21、你对前端有什么理解?

    1.6K20

    前端开发,关键技术点杂烩

    父函数定义的变量在子函数的作用域链中,子函数没有被销毁,其作用域链中所有变量和函数就会被维护,不会被销毁。...20、JS 作用域链 在一些类 C 的语言中有“块级作用域”,即花括号的每一段代码都有自己的独立作用域,而 JS 只有函数级作用域;JS 作用域链的第一个对象始终是当前执行代码所在环境的变量对象(VO)...,声明函数在全局作用域,此时作用域链只有一个环境对象;运行函数时作用域链顶端加入了函数内的环境对象,运行完毕时顶端环境对象被销毁,以此类推。...JS 在查找变量时会从链的顶端(就近原则)一直向下查找。如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。...全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。 (最好和闭包一起理解) 21、你对前端有什么理解?

    1.1K30

    通过 PHP 原生代码实现视图模板引擎的解析和渲染

    在此之前,我们的视图渲染实现比较简单粗暴,就是直接通过 include 语句引入对应的 PHP 视图模板,然后在当前作用域内有效的变量会在引入的视图模板中生效,以博客应用首页为例,对应的视图引入代码是这样的...不过为了让上述视图渲染实现代码更加优雅、便于维护和扩展,我们以面向对象风格的代码对其进行重构,并且将其调整为支持其他模板引擎。...,我们通过 PHP 自带的输出控制函数 ob_start 打开输出控制缓冲,然后调用 extract 函数将从外部传入的数组变量导入当前符号表(即在当前作用域内以数组键名作为变量名,以对应键值作为变量值...重点看下 render 方法,该方法用于被上层代码调用完成视图模板的解析和渲染,在这个方法中,我们通过 getContent 方法调用系统当前使用的模板引擎实例 $engine 的 extract 方法...函数组合当前作用域内的变量传入(以变量名作为键,变量值作为值构建关联数组,组合结果和前一种形式完全一样)。

    2.1K10
    领券