jedrzej/searchable

用于Laravel Eloquent模型的搜索/过滤特性 - 使用请求参数过滤模型

0.0.17 2019-09-05 08:09 UTC

README

此包为Laravel 4/5/6的Eloquent模型添加搜索/过滤功能。

以下包可能对您也有用

  • Withable - 允许使用请求参数进行关系预加载
  • Sortable - 允许使用请求参数对模型进行排序
  • Pimpable - 一个组合了Sortable、Searchable和Withable行为的元包

Composer安装

将以下行添加到项目中composer.json文件中

"jedrzej/searchable": "0.0.17"

或者在项目的根目录下命令行中运行以下命令

composer require "jedrzej/searchable" "0.0.17"

设置可搜索模型

为了让Eloquent模型可搜索,将特性添加到模型中并定义一个模型可以过滤的字段列表。您可以定义一个 $searchable 属性或者实现一个 getSearchableAttributes 方法,如果想要执行一些逻辑来定义可搜索字段列表。

use Jedrzej\Searchable\SearchableTrait;

class Post extends Eloquent
{
	use SearchableTrait;
	
	// either a property holding a list of searchable fields...
	public $searchable = ['title', 'forum_id', 'user_id', 'created_at'];
	
	// ...or a method that returns a list of searchable fields
	public function getSearchableAttributes()
	{
	    return ['title', 'forum_id', 'user_id', 'created_at'];
	}
}

为了使所有字段可搜索,在可搜索字段列表中放入一个星号 *。

public $searchable = ['*'];

也可以黑名单模型属性,以防止它们被过滤。

您可以定义一个 $notSearchable 属性或实现一个 getNotSearchableAttributes 方法,如果想要执行一些逻辑来定义可搜索字段列表。

use Jedrzej\Searchable\SearchableTrait;

class Post extends Eloquent
{
	use SearchableTrait;
	
	// either a property holding a list of not searchable fields...
	public $notSearchable = ['created_at'];
	
	// ...or a method that returns a list of not searchable fields
	public function getNotSearchableAttributes()
	{
	    return ['created_at'];
	}
}

如果定义了这两个列表 - 可搜索和不可搜索的列 - 最终的可搜索字段集将包含所有白名单属性,除了所有黑名单属性。

搜索模型

SearchableTrait 为模型添加了一个 filtered() 范围 - 您可以传递一个查询数组作为过滤条件

// return all posts with forum_id equal to $forum_id
Post::filtered(['forum_id' => $forum_id])->get();

// return all posts with with <operator> applied to forum_id
Post::filtered(['forum_id' => <operator>])->get();

或者它将使用 Request::all() 作为默认值

// if you append ?forum_id=<operator> to the URL, you'll get all Posts with <operator> applied to forum_id
Post::filtered()->get();

选择查询模式

默认查询模式是将所有查询的合取(AND)应用于可搜索模型。可以通过将 mode 查询参数的值设置为 or 来将其更改为析取(OR)。如果已经使用了 mode 查询参数,则将使用 getQueryMode 方法返回的名称。

构建查询

SearchableTrait 支持以下运算符

比较运算符

比较运算符允许根据模型属性与查询值的比较结果进行过滤。它们适用于字符串、数字和日期。它们的格式如下

(<operator>)<value>

以下比较运算符可用

  • gt 用于 大于 比较运算
  • ge 用于 大于等于 比较运算
  • lt 用于 小于 比较运算,例如
  • le 用于 小于等于 比较运算

为了过滤2015年和更新的帖子,应使用以下查询

?created_at=(ge)2015-01-01

等于/在运算符

Searchable 特性允许根据属性的精确值或值集进行过滤,具体取决于传递给查询参数的值的类型。如果值包含逗号,则参数在逗号处拆分并用作 IN 过滤的数组输入,否则应用精确匹配。

为了过滤ID为42的用户帖子,应使用以下查询

?user_id=42

为了过滤ID为7或8的论坛帖子,应使用以下查询

?forum_id=7,8

类似运算符

类似操作符允许使用LIKE查询进行筛选。如果使用精确匹配操作符,但值以%符号作为第一个或最后一个字符时,则会触发此操作符。

为了筛选以How开头的帖子,应使用以下查询

?title=How%

注意:百分号字符用于对URL中的特殊字符进行编码,因此在发送请求时,请确保您使用的工具正确地将%字符编码为%25

空操作符

(null)空操作符允许筛选属性为空的模型。

为了筛选没有附件的帖子,应使用以下查询

?attachment_id=(null)

否定操作符

可以通过在操作符前添加!来获取查询的否定结果。

一些示例

//filter posts from all forums except those with id 7 or 8
?forum_id=!7,8

//filter posts older than 2015
?created_at=!(ge)2015

//filter posts with attachment
?attachment_id=!(null)

单个属性的多重约束

可以为单个模型属性应用多个约束。为了实现这一点,提供查询过滤器的数组而不是单个过滤器

// filter all posts from year 20** except 2013
?created_at[]=20%&created_at[]=!2013%

按关系属性筛选

可以按模型关系的属性进行筛选——将应用Eloquent的whereHas()。为了按关系筛选,将关系属性添加到searchable字段列表中,形式为relation:attribute。在查询中应使用相同的字符串来按该关系的属性进行筛选,例如

 // allow filtering on user's active field
 protected $searchable = ['user:active'];

 // filter only posts of active users
 ?user:active=1

也可以通过应用Eloquent的whereDoesntHave()来否定搜索并筛选没有匹配关系的对象。为了这样做,需要在关系名称前加上!

 // allow filtering on comment's approved field
 protected $searchable = ['comments:approved'];

 // filter only posts that have approved comments
 ?comments:approved=1
      
 // filter only posts that have not-approved comments
 ?comments:approved=1
 
 // filter only posts that do not have approved comments
 ?!comments:approved=1

如果您想要按嵌套关系进行筛选,只需提供带有冒号代替点的嵌套关系名称即可。这是必要的,因为PHP会自动将点替换为下划线。

 // filter only posts that have comments from active authors
 ?comments:author:active=1

覆盖默认筛选逻辑

可以处理选定的过滤器以使用自己的逻辑,例如,当筛选器名称与用于筛选的属性名称不匹配时,或者需要执行某些自定义操作。为了覆盖xyz筛选器的逻辑,您需要在您的模型中定义一个名为processXyzFilter的方法。如果筛选器已处理且默认逻辑不应再发生,则此方法应返回true

 // use one filter to search in multiple columns
 protected function processNameFilter(Builder $builder, Constraint $constraint)
 {
     // this logic should happen for LIKE/EQUAL operators only
     if ($constraint->getOperator() === Constraint::OPERATOR_LIKE || $constraint->getOperator() === Constraint::OPERATOR_EQUAL) {
         $builder->where(function ($query) use ($constraint) {
             $query->where('first_name', $constraint->getOperator(), $constraint->getValue())
                 ->orWhere('last_name', $constraint->getOperator(), $constraint->getValue());
         });

         return true;
     }

     // default logic should be executed otherwise
     return false;
 }

为了覆盖关系搜索的筛选器,将筛选器名称中的冒号替换为下划线。如果您想覆盖user:active的逻辑,您需要定义processUser_ActiveFilter方法。