ahmedabdo/searchable

为 Laravel 模型添加搜索功能的包

v1.0.10 2023-10-06 19:02 UTC

This package is auto-updated.

Last update: 2024-09-22 14:40:38 UTC


README

Laravel Searchable 是一个包,它为 Laravel Eloquent 模型添加了简单可定制的搜索和筛选功能

安装

composer require ahmedabdo/searchable

搜索

搜索使用示例

  • 在您的模型中使用 Abdo\Searchable\Searchable 特性。
  • 在 searchable 数组中定义您要用于搜索的列。
  • 利用搜索作用域在所选列上执行搜索。
// model
use Abdo\Searchable\Searchable;
use Abdo\Searchable\Attributes\SearchAdd;
use Abdo\Searchable\Attributes\SearchColumns;
class User extends Authenticatable
{
    use Searchable;
	
    #[SearchColumns]
    public $searchable = [
	"columns" => [
	    "name",
	    "email",
	    "role.name",
	    "created_at"
	],
	"eager" => [
	    "role"
	]
    ];

    #[SearchAdd("created_at")]
    public function searchByCreatedAtDayName(Builder $q, string $searchWord) {
        $q->orWhereRaw("DAYNAME(created_at) like ?", ["%" . $searchWord . "%"]);
    }
}

// usage 

User::search($searchWord)->get();

搜索列

要定义模型的搜索列,您可以使用带有 #[SearchColumns] 属性的属性装饰。此属性将包含搜索模型的默认列以及需要预加载的任何关系。如果没有设置 #[SearchColumns] 属性,则将使用可填充列作为后备。

#[SearchColumns]
public $searchable = [
    "columns" => [
        "colame",
	"relation.colname",
        "relation.relation.colname",
    ],
    "eager" => [
        "relation"
    ]
];

自定义搜索

如果您想为特定列自定义搜索查询,您可以创建一个带有 #[Search("colname")] 属性的方法,并针对该选择的列构建自定义查询。

#[SearchColumns]
public $searchable = [
    "columns" => [
        "time", // stored as Y-m-d H:i:s
    ]
];

#[Search("time")]
public function searchTime(Builder $q, string $searchWord) {
     $q->orWhere("time", "like", "%" . $searchWord . "%")
       ->orWhereRaw("DAYNAME(time) like ?", ["%" . $searchWord . "%"]);
}

在上面的示例中,"time" 列在数据库中以日期时间值存储。如果您想通过天名来定制该列的搜索功能,并添加一个新的或 where 语句进行搜索,您可以使用 #[SearchAdd("colname")] 属性。

通过使用此属性,您可以将所需的或 where 语句纳入列搜索查询中,同时利用由包提供的现有搜索查询。

注意

您可以使用任意数量的 searchAdd 方法。

#[SearchAdd("time")]
public function searchTimeByDayName(Builder $q, string $searchWord) {
     $q->orWhereRaw("DAYNAME(time) like ?", ["%" . $searchWord . "%"]);
}

如果您已使用 #[Search("colname")]#[SearchAdd("colname")] 自定义关系搜索,则传递给自定义方法的构建器实例将是关系模型的构建器。

public $searchable = [
    "columns" => [
        "patient.name",
    ]
];

#[Search("patient.name")]// or #[SearchAdd("patient.name")]
public function searchPatientName(Builder $q, string $searchWord) {
     // $q is builder instance for Patient model 
     $q->orWhere("name", "like", "%" . $searchWord . "%");
}

覆盖默认列

如果您想覆盖模型中定义的列,则可以将列作为第二个参数传递给搜索作用域。

User::search($searchWord, ["fname", "lname"])->get();

搜索选项

可以为列添加一个选项数组

#[SearchColumns]
public $searchable = [
    "columns" => [
        "name" => ["operator" => "="]
    ]
];

User::search($searchWord,[
    "name" => ["operator" => "=", "useCustom" => false, "useAddCondition" => false] 
])

列可以有三种选项

筛选

筛选使用示例

// model
use Abdo\Searchable\Searchable;
class User extends Authenticatable
{
     use Searchable;

     #[SearchColumns]
     public $searchable = [
        "columns" => [
            "name",
            "email",
            "role.name",
            "created_at"
        ],
        "eager" => [
            "role"
        ]
    ];
}

//request query string :
// ?name=ahmed&email=startsWith|ahmed&role:name=admin&created_at=from|2020-01-01 

// usage 
User::filter()->get();

筛选列

默认情况下,用于筛选的列将是定义在具有 #[SearchColumns] 属性的属性中的列,结合在可填充数组中指定的列。如果您想将不同的列用作筛选的默认值,则可以定义一个具有 #[FilterColumns] 属性的属性。

#[FilterColumns]
public $filterable = [
	"name","email", //... 
];

筛选查询字符串

查询字符串参数名称应与列名称匹配。如果您正在筛选关系,则可以使用冒号 : 作为关系名称和列名称之间的分隔符,而不是点 . 查询字符串应遵循此模式。

// ?<colname>=<operator, default:"=">|<value>

User::filter()->get();

如果您已使用与列名称不同的参数名称,则可以将列名称和筛选值传递给筛选作用域。

// ?<not-colname>=<operator, default:"=">|<value>
// To retrieve the filter value from the query string, you can utilize the "filterParam" helper

User::filter(["column_name" => filterParam("not_column_name")])->get();

// Note that if the rest of the query string parameter names match the column names
// you can employ a similar approach.
User::filter(["column_name" => filterParam("not_column_name")])->filter()->get(); 

运算符

允许用于筛选的运算符包括可以发送到 where 构建器方法的所有运算符,以及额外的运算符。

注意

在使用“between”运算符时,必须提供两个参数,用逗号分隔。如果未指定from参数,则数据将过滤从负无穷大到to参数。同样,如果未提供to参数,则数据将过滤到正无穷大。例如:?created_at=bt|,2010-01-01检索所有在2010年1月1日之前创建的记录。另一个例子:?created_at=bt|2010-01-01,检索所有在2010年1月1日之后创建的记录。

筛选模式

有两种过滤模式:and模式和or模式,默认模式是and
更改模式的方法

    // using or mode
    User::filter(mode: Mode::OR)->get();

    // using and mode
    User::filter(mode: Mode::AND)->get();
    User::filter()->get();

筛选 Blade 脚本

如果您在前端使用常规Blade模板,有一个简单的JavaScript脚本可用于简化创建过滤器表单。要包含此脚本,将@searchableScripts指令添加到主布局中。

然后您可以按照以下步骤创建过滤器表单

用法

  • 确保表单有filter
  • 输入名称应与相应的列名称匹配
  • 对于关系,使用冒号:作为分隔符,例如:relation:columnName
  • data-filter属性中设置所需的过滤运算符,默认为=
  • 使用filterValue("queryParam")获取过滤值
<!-- give the form class  'filter' -->
<form action="" class="filter">
    <label for="">Age</label>
    <!-- place the filter operator in 'data-filter' attribute  -->
    <!-- filterValue helper for getting the current filter value  -->
    <input data-filter=">" type="number" value="{{filterValue('age')}}" name="age" id="">
    
    <label for="">Created At From</label>
    <!-- for bte, bt, betweenEqual, between operators  -->
    <!-- ex: from input with name created_at[0] to input with name created_at[1]  -->
    <input data-filter="bt" type="date" value="{{filterValue('created_at', asArray: true)[0] ?? now()->format('Y-m-d')}}" name="created_at[0]" id="">

    <label for="">Created At To</label>
    <input type="date" value="{{filterValue('created_at', asArray: true)[1] ?? now()->format('Y-m-d')}}" name="created_at[1]" id="">
			
    <!-- ex: for multi value   -->
    <label for="">Role</label>
    <select data-filter="in"  name="role_id[]" id="" multiple>
        <option value="0">admin</option>
        <option value="1">manager</option>
        <option value="2">employee</option>
    </select>

    <button type="submit" >filter</button>
</form>

筛选助手

filterParam

"filterParam"辅助函数用于从查询字符串中提取过滤值。当使用Blade过滤器表单时,应使用此辅助函数,尤其是如果输入字段名称与对应列名称不同。

//model
#[SearchColumns]
public $searchable = [
    "columns" => [
        "name"
    ],
];

//blade
<form action="" class="filter">
    <input data-filter="contains" type="text" value="{{filterValue('empName')}}" name="empName" id="">
</form>

//usage
User::filter(["name" => filterParam("empName")])->get();

filterValue

"filterValue"辅助函数用于检索用于过滤的值,以便在输入字段中显示此值,作为一个示例。

//?name=cont|ahmed&role_id=in|2,3,4

filterValue("name") // ouptut ahmed
filterValue("role_id") // output 2,3,4
filterValue("role_id", true) //output [2,3,4]

自定义运算符

如果您需要定义用于过滤和搜索的自定义运算符,有两种不同的方法。

注意

自定义运算符必须以sp_开头

在配置中
要发布配置文件,请执行以下命令

php artisan vendor:publish --provider="Abdo\Searchable\ServiceProvider"

配置文件发布后,您可以在operators数组中定义自己的自定义运算符。

    "operators" => [

        "sp_is_null" => function (Builder $builder, string $column, string $word) {
            return $builder->whereIsNull($column)->orWhere($column, 0);
        },
    ],

在服务提供者中

此外,您还可以在某个服务提供者的boot方法中注册自定义运算符。

    ColumnConfigraution::registerOperator("sp_is_null", function (Builder $builder, string $column, string $word) {
        return $builder->whereIsNull($column)->orWhere($column, 0);
    });

    //after defining your custom operator you can use them like this
    //?status=sp_is_null|