首页 > 其他分享 >Laravel 中 scope 查询作用域

Laravel 中 scope 查询作用域

时间:2023-03-24 13:03:56浏览次数:28  
标签:Laravel get 作用域 查询 query scope 全局 where


阅读目录

  • 一、查询作用域
  • 1.1 全局作用域
  • 1 编写全局作用域
  • 2 匿名全局作用域
  • 3 取消全局作用域
  • 1.2 本地作用域
  • 1 编写本地作用域
  • 2 动态作用域
  • 二、应用示例
  • 三、简单演示理解示例

一、查询作用域

1.1 全局作用域

全局作用域可以给模型的查询都添加上约束。
Laravel 的 软删除 功能就是利用此特性从数据库中获取 「未删除」的模型。
你可以编写你自己的全局作用域,很简单、方便的为每个模型查询都加上约束条件:

1 编写全局作用域

编写全局作用域很简单。
定义一个实现 Illuminate\Database\Eloquent\Scope 接口的类,并实现 apply 这个方法。
根据你的需求,在 apply 方法中加入查询的 where 条件:

<?php

namespace App\Scopes;

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

class AgeScope implements Scope
{
    /**
     * 把约束加到 Eloquent 查询构造中。
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('age', '>', 200);
    }
}

{tip} 如果需要在 select 语句里添加字段,应使用 addSelect 方法,而不是 select 方法。
这将有效防止无意中替换现有 select 语句的情况。

应用全局作用域
要将全局作用域分配给模型,需要重写模型的 boot 方法并使用 addGlobalScope 方法:

<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     *  模型的 「启动」 方法.
     *  @return void
     */
    protected static function boot()
    {
        parent::boot();
        static::addGlobalScope(new AgeScope);
    }
}

添加作用域后,对 User::all() 的查询会生成以下 SQL 查询语句:

select * from `users` where `age` > 200

2 匿名全局作用域

Eloquent 同样允许使用闭包定义全局作用域,这样就不需要为一个简单的作用域而编写一个单独的类:

<?php

namespace App;

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

class User extends Model
{
    /**
     *模型的「启动」方法.
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('age', function (Builder $builder) {
            $builder->where('age', '>', 200);
        });
    }
}

3 取消全局作用域

如果需要对当前查询取消全局作用域,需要使用 withoutGlobalScope 方法。
该方法仅接受全局作用域类名作为它唯一的参数:

User::withoutGlobalScope(AgeScope::class)->get();

或者,如果使用闭包定义全局作用域的话:

User::withoutGlobalScope('age')->get();

如果你需要取消部分或者全部的全局作用域的话,需要使用 withoutGlobalScopes 方法:

// 取消所有的全局作用域...
User::withoutGlobalScopes()->get();

// 取消部分全局作用域...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();

1.2 本地作用域

本地作用域允许定义通用的约束集合以便在应用程序中重复使用。
例如,你可能经常需要获取所有 「流行」的用户。

1 编写本地作用域

要定义这样一个范围,只需要在对应的 Eloquent 模型方法前添加 scope 前缀:

作用域总是返回一个查询构造器实例:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 只查询受欢迎的用户的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * 只查询 active 用户的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

使用本地作用域

一旦定义了作用域,就可以在查询该模型时调用作用域方法。
不过,在调用这些方法时不必包含 scope 前缀。
甚至可以链式调用多个作用域,例如:

$users = App\User::popular()->active()->orderBy('created_at')->get();

借助 or 查询运行符整合多个 Eloquent 模型,可能需要使用闭包回调:

$users = App\User::popular()->orWhere(function (Builder $query) {
    $query->active();
})->get();

因为这样可能会有点麻烦,Laravel 提供了「高阶的」 orWhere 方法,它允许你在链式调用作用域时不使用闭包:

$users = App\User::popular()->orWhere->active()->get();

2 动态作用域

有时可能地希望定义一个可以接受参数的作用域。
把额外参数传递给作用域就可以达到此目的。
作用域参数要放在 $query 参数之后:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 将查询作用域限制为仅包含给定类型的用户。
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @param  mixed $type
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfType($query, $type)
    {
        return $query->where('type', $type);
    }
}

这样就可以在调用作用域时传递参数了:

$users = App\User::ofType('admin')->get();

二、应用示例

$user  = new ChatUser();
$chat_user = $user::scopeNickName($user,"大金")->get();
dd($chat_user->toArray());

运行结果

rray:1 [
  0 => array:35 [
    "id" => 87
    "mpid" => 1
    "openid" => "oYxpK0RsvcwgS9DtmIOuyb_BgJbo"
    "nickname" => "大金"
    "headimgurl" => "https://img-home.csdnimg.cn/images/20210817021749.png"
    "sex" => 1
    "subscribe" => 1
    "subscribe_time" => 1508920878
    "unsubscribe_time" => null
    "relname" => null
    "signature" => null
    "mobile" => null
    "is_bind" => 0
    "language" => "zh_CN"
    "country" => "中国"
    "province" => "河南"
    "city" => "商丘"
    "remark" => ""
    "group_id" => 0
    "groupid" => 0
    "tagid_list" => "[]"
    "score" => 0
    "money" => "0.00"
    "latitude" => null
    "longitude" => null
    "location_precision" => null
    "type" => 0
    "unionid" => null
    "password" => null
    "last_time" => 586969200
    "parentid" => 1
    "isfenxiao" => 0
    "totle_earn" => "0.00"
    "balance" => "0.00"
    "fenxiao_leavel" => 2
  ]
]

三、简单演示理解示例

在model中,创建加上一个 scope 前缀的方法即可。

class News extends Model
{
    const TABLE = 'news';

	//只包含展示的新闻的查询作用域
    public function scopeScoShow($query)
    {
        return $query->where('is_show', 1);
    }

	//只包含某个类型的查询作用域,带参数
    public function scopeScoType($query, $type)
    {
        return $query->where('type', $type);
    }

}

调用

//使用时调用,首字母小写
News::scoShow()->get();

//带参数
News::scoShow()->scoType(2)->get();


标签:Laravel,get,作用域,查询,query,scope,全局,where
From: https://blog.51cto.com/u_13571520/6147105

相关文章

  • Laravel 常用辅助函数
    阅读目录Laravel常用辅助函数辅助函数array_dot()辅助函数允许你将多维数组转换为使用点符号的一维数组array_get()函数使用点符号从多维数组中检索值public_path()返回......
  • Laravel 异常错误信息处理
    手动抛出错误try{ $num1=3; if($num1==3){ thrownew\Exception("自定义错误"); }}catch(\Exception$exception){ info($exception->getMessage());}日......
  • laravel-s实现高性能webSocket服务
    laravel-s实现高性能webSocket服务1安装基于LaravelS构建HTTP服务器2在Laravel中集成Swoole实现WebSocket服务器1修改配置文件2创建WebSocketService类3测......
  • laravel 利用中间件进行操作日志记录
    利用中间件进行操作日志记录过程:1、创建中间件phpartisanmake:middlewareAdminOperationLog2、生成了文件./app/Http/Middleware/AdminOperationLog.php代码如下:<?phpn......
  • laravel 利用监听器进行sql语句记录
    利用监听器进行sql语句记录1、监听sql语句的事件类已经定义,直接创建监听器类即可:#监听sqlmake:listenerQueryListener--event=Illuminate\Database\Events\QueryExecute......
  • JavaScript Scope All In One
    JavaScriptScopeAllInOneGlobalScope/全局作用域ScriptScope/脚本作用域LocalScope/局部作用域(函数作用域)BlockScope/块级作用域({}作用域)C......
  • 作用域和构造器
    1.作用域上部分承接course-322.作用域注意事项2372.1例publicclassTest33{publicstaticvoidmain(String[]args){Tt1=newT();//属性生命周期......
  • laravel 创建控制器创建目录方法
    控制器  phpartisanmake:controllerAdmin\SystemController路由   Route::get('/sa','Admin\StudentController@chaxun');控制器  phpartisanmake:contr......
  • Day 17 17.1 python之变量的作用域
    一、变量作用域变量的作用域Python是静态作用域,也就是说Python中,变量的作用域源于它在代码中的位置在不同的位置,可能有不同的命名空间。命名空间是变量作用域的体现......
  • laravel 单控制器用法
    第一,定义路由Route::get('/hello','UserController');第二,控制定义__invokenamespaceApp\Http\Controllers;useIlluminate\Http\Request;classUserControllerext......