介绍

当我们想返回一个由多个参数过滤的用户列表。如下:

/users?name=er&last_name=&company_id=2&roles[]=1&roles[]=4&roles[]=7&industry=5

$request->all() 返回如下:

[
    'name'       => 'er',
    'last_name'  => '',
    'company_id' => '2',
    'roles'      => ['1','4','7'],
    'industry'   => '5'
]

要按所有参数进行过滤,我们需要编码如下:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\User;

class UserController extends Controller
{

    public function index(Request $request)
    {
        $query = User::where('company_id', $request->input('company_id'));

        if ($request->has('last_name'))
        {
            $query->where('last_name', 'LIKE', '%' . $request->input('last_name') . '%');
        }

        if ($request->has('name'))
        {
            $query->where(function ($q) use ($request)
            {
                return $q->where('first_name', 'LIKE', $request->input('name') . '%')
                    ->orWhere('last_name', 'LIKE', '%' . $request->input('name') . '%');
            });
        }

        $query->whereHas('roles', function ($q) use ($request)
        {
            return $q->whereIn('id', $request->input('roles'));
        })
            ->whereHas('clients', function ($q) use ($request)
            {
                return $q->whereHas('industry_id', $request->input('industry'));
            });

        return $query->get();
    }

}

使用 Eloquent Filters 写法如下:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\User;

class UserController extends Controller
{

    public function index(Request $request)
    {
        return User::filter($request->all())->get();
    }

}

配置

安装

composer require tucker-eric/eloquentfilter

定义一个模型过滤器有以下几种方法:

  • 使用 Eloquent Filter 的默认设置
  • 对所有过滤器使用自定义命名空间
  • 定义模型的默认过滤器
  • 动态选择模型的过滤器

默认设置

所有过滤器的默认命名空间都是 App\ModelFilters\,并且每个 Model 都希望过滤器类名遵循 {$ModelName}Filter 命名规范,而不管模型所在的空间。以下是模型以及各自基于默认命名规范的过滤器示例。

模型ModelFilter
AppUserAppModelFiltersUserFilter
AppFrontEndPrivatePostAppModelFiltersPrivatePostFilter
AppFrontEndPublicGuestPostAppModelFiltersGuestPostFilter

Laravel

使用配置文件(可选)

注册服务提供者(Service Provider)后,您可以使用 php artisan model:filter {model} 命令,并允许发布您的配置文件。注册服务提供者不是必须的,只有在您想要更改默认命名空间或使用 artisan 命令时才需要。

安装 Eloquent Fiter 包后,在 config/app.php 配置文件中添加 EloquentFilter\ServiceProvider::class

' providers '  => [
    //其他服务提供者......    
    
    EloquentFilter \ ServiceProvider :: class
],

使用 publish 命令将配置文件发布到本地配置:

php artisan vendor:publish --provider="EloquentFilter\ServiceProvider"

修改 config/eloquentfilter.php 文件,设置您的模型过滤器命名空间:

'namespace' => "App\\ModelFilters\\",

Lumen

注册服务提供者(可选)

仅在您要使用该php artisan model:filter命令时才需要此选项。

修改 bootstrap/app.php:

$app->register(EloquentFilter\LumenServiceProvider::class);

修改默认的命名空间,修改 bootstrap/app.php:

config(['eloquentfilter.namespace' => "App\\Models\\ModelFilters\\"]);

定义默认的模型过滤器

在您的模型里创建一个 public 属性的方法 modelFilter(), 然后返回 $this->provideFilter(Your\Model\Filter::class)

<?php

namespace App;

use EloquentFilter\Filterable;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Filterable;

    public function modelFilter()
    {
        return $this->provideFilter(App\ModelFilters\CustomFilters\CustomUserFilter::class);
    }

    //User Class
}

动态过滤器

您可以通过传递 filter() 方法的第二个参数来定义一个动态过滤器,动态定义过滤器将优先于为模型定义的任何其他过滤器。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\User;
use App\ModelFilters\Admin\UserFilter as AdminFilter;
use App\ModelFilters\User\UserFilter as BasicUserFilter;
use Auth;

class UserController extends Controller
{
    public function index(Request $request)
    {
        $userFilter = Auth::user()->isAdmin() ? AdminFilter::class : BasicUserFilter::class;

        return User::filter($request->all(), $userFilter)->get();
    }
}

生成过滤器

仅当您在 config/app.php 中的 providers 数组中注册 EloquentFilter\ServiceProvider::class 时才可用

您可以用以下 artisan 命令创建一个模型过滤器:

php artisan model:filter User

此命令将会为您的 User 模型在 app/ModelFilters/UserFilter.php 位置创建过滤器。此命令还支持 psr-4。您只需要确保转义类名中的反斜杠(/)。例如:

php artisan model:filter AdminFilters\\User

此命令将会创建 app/ModelFilters/AdminFilters/UserFilter.php

用法

定义过滤器逻辑

根据要过滤参数驼峰形式定义 传给 filter() 方法来定义逻辑

  • 忽略空字符串
  • 无论参数是什么,setup() 方法都将会被调用
  • 从参数端删除 _id 以定义方法,因此过滤 user_id 将使用 user() 方法
  • 没有对应过滤方法的参数会被忽略
  • 参数对应的值将会被注入方法中
  • 所有值都可以通过 $this->input() 方法访问,或者通过键 $this->input($key) 访问单个值
  • 模型过滤器类中可以访问所有 Eloquent Builder 方法

要为以下输入定义方法:

[
    'company_id'   => 5,
    'name'         => 'Tuck',
    'mobile_phone' => '888555'
]

做法如下:

use EloquentFilter\ModelFilter;

class UserFilter extends ModelFilter
{
    protected $blacklist = ['secretMethod'];
    
    // This will filter 'company_id' OR 'company'
    public function company($id)
    {
        return $this->where('company_id', $id);
    }

    public function name($name)
    {
        return $this->where(function($q) use ($name)
        {
            return $q->where('first_name', 'LIKE', "%$name%")
                ->orWhere('last_name', 'LIKE', "%$name%");
        });
    }

    public function mobilePhone($phone)
    {
        return $this->where('mobile_phone', 'LIKE', "$phone%");
    }

    public function setup()
    {
        $this->onlyShowDeletedForAdmins();
    }

    public function onlyShowDeletedForAdmins()
    {
        if(Auth::user()->isAdmin())
        {
            $this->withTrashed();
        }
    }
    
    public function secretMethod($secretParameter)
    {
        return $this->where('some_column', true);
    }
}

注意: 在上面的示例中,如果不想从删除输入参数末尾的 _id,则可以在过滤器上设置 protected $drop_id = false。这样将允许您拥有 company() 过滤器方法和 companyId() 过滤器方法。

注意: 在上面的示例中,每次调用 filter() 时, setup() 中所有方法都会被调用

黑名单

所有定义在黑名单数组中的方法都不会被过滤。这些方法通常用于过滤器内部逻辑。

blacklistMethod()whitelistMethod() 方法被用于动态黑名单和白名单。

在上面的例子中,数组中即使有 secret_methodsecretMethod() 也不会被调用。要调用此方法,需要动态列入白名单:

Example:

public function setup()
{
    if(Auth::user()->isAdmin()) {
        $this->whitelistMethod('secretMethod');
    }
}

其他过滤方法

Filterable trait 还有以下 query builder 帮助方法:

EqoquentFilter MethodQueryBuilder Equivalent
$this->whereLike($column, $string)$this->where($column, 'LIKE', '%'.$string.'%')
$this->whereBeginsWith($column, $string)$query->where($column, 'LIKE', $string.'%')
$this->whereEndsWith($column, $string)$query->where($column, 'LIKE', '%'.$string)

可以从任何 use Filterable 的模型中调用这些方法。

为一个模型应用过滤器

在任意 Eloquent Model 上实现 EloquentFilter\Filterable trait

<?php

namespace App;

use EloquentFilter\Filterable;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Filterable;

    //User Class
}

然后你可以在模型上调用 filter() 方法,此方法接收一个要过滤数组:

class UserController extends Controller
{
    public function index(Request $request)
    {
        return User::filter($request->all())->get();
    }
}

原文文档