Eloquent 过滤器
建议编辑介绍
Eloquent 过滤器是用于在 Laravel 中创建复杂查询的强大工具。 它们允许您轻松管理和自定义搜索条件。 您可以使用 Eloquent 过滤器根据属性、品牌和其他条件过滤产品目录。
要创建新的 Eloquent 过滤器,可以使用 php artisan orchid:filter
命令,后跟所需的过滤器名称。
此命令将在 app/Orchid/Filters
文件夹中生成一个新的过滤器类。
以下是创建 EmailFilter
的示例:
php artisan orchid:filter EmailFilter
生成的过滤器类如下所示:
namespace App\Http\Filters;
use Orchid\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
class EmailFilter extends Filter
{
/**
* 匹配参数的数组。
*
* @var array
*/
public $parameters = ['email'];
/**
* 如果请求参数满足,则应用过滤器。
*
* @param Builder $builder
*
* @return Builder
*/
public function run(Builder $builder): Builder
{
return $builder->where('email', $this->request->get('email'));
}
/**
* 获取显示字段。
*
* @return Field[]
*/
public function display(): array
{
return [
Input::make('email')
->type('text')
->value($this->request->get('email'))
->placeholder('搜索...')
->title('搜索')
];
}
}
要在自己的模型中使用过滤器,
需要连接 Orchid\Filters\Filterable
trait,并将类数组传递给 filters
函数:
use App\Model;
Model::filters([EmailFilter::class])->simplePaginate();
为不同模型使用过滤器
过滤器的一个巨大优势是可以为不同模型重用相同的过滤器类。 这允许您定义一次过滤器并将其应用于多个模型,减少代码重复。 只需在应用过滤器到模型时指定过滤器类:
$filters = [
EmailFilter::class,
];
User::filters($filters)
->simplePaginate();
Customer::filters($filters)
->simplePaginate();
始终运行过滤器
默认情况下,只有在指定相应参数时才会应用过滤器。
但是,如果希望在每个请求上运行过滤器,可以将过滤器类中的 $parameters
属性留为空数组。
这样,过滤器将应用于所有查询。例如:
public $parameters = [];
此外,如果 display
方法返回的数组为空,过滤器将不会出现在界面中,但仍将在查询中保持功能。这允许灵活配置,使某些过滤器在后台静默运行。
参数模式
过滤器提供了使用便捷语法定义参数模式的能力。 这允许您创建自定义模式并根据特定模式执行高级过滤。例如:
/**
* 匹配参数的数组。
*
* @var null|array
*/
public $parameters = [
'pattern.*',
];
在上述示例中,过滤器将匹配任何符合 pattern.*
模式的参数。这允许您在过滤器中处理广泛的动态参数。
自定义过滤器显示值
默认情况下,过滤器值以 name:value
格式显示,这对于广泛的过滤器非常有效。然而,当处理 ID 或系统名称时,您可能希望显示更友好的值。
为此,您可以定义一个返回字符串的 value
方法。例如:
public function value(): string
{
return '您的自定义值';
}
如果应用了过滤器,此字符串将在用户界面中显示。
这种方法在使用依赖于 ID 或系统特定名称的过滤器时特别有用,允许您为最终用户提供更有意义或描述性的输出。
选择
“选择” 层提供了一种方便的方法来分组和组织过滤器,以便将它们显示和应用于模型。 此层充当用户界面和模型之间的中介,简化了过滤器管理过程。
要创建 “选择” 层,可以使用以下命令:
php artisan orchid:selection MailingSelection
此命令将在 App\Orchid\Layouts
目录中生成一个名为 MailingSelection
的新 PHP 文件。
在此类中,您将找到一个名为 filters()
的方法。
此方法是您应列出所有需要显示和应用的过滤器的地方。
例如,假设您想显示和应用两个过滤器:一个电子邮件过滤器和一个创建过滤器。
您的 MailingSelection
类将如下所示:
namespace App\Orchid\Layouts;
use App\Orchid\Filters\EmailFilter;
use App\Orchid\Filters\CreatedFilter;
use Orchid\Screen\Layouts\Selection;
class MailingSelection extends Selection
{
/**
* @return Filter[]
*/
public function filters(): array
{
return [
EmailFilter::class,
CreatedFilter::class
];
}
}
定义 MailingSelection
类中的过滤器后,可以通过使用 filters()
方法将它们应用于模型。例如:
Model::filters(MailingSelection::class)->simplePaginate();
通过在模型上调用 filters()
方法并传递 MailingSelection::class
作为参数,可以将 MailingSelection
类中定义的过滤器应用于模型。
在屏幕上显示
“选择” 层还可以用于在屏幕上显示过滤器。
在屏幕的 layout()
方法中,可以包含 MailingSelection
类以在屏幕上显示过滤器。
例如:
use App\Orchid\Layouts\MailingSelection;
public function layout(): array
{
return [
MailingSelection::class,
];
}
请注意,具有空字段的过滤器将不会被渲染,以确保界面简洁和用户友好。
使用模板自定义
选择层的外观可以有所不同,例如显示为下拉列表(默认)或表单。您可以使用 template
属性定义此项。例如:
class MailingSelection extends Selection
{
/**
* 渲染选择的模板。
*
* 您可以使用任何 Blade 模板。默认:
* - `self::TEMPLATE_LINE` 用于线性布局
* - `self::TEMPLATE_DROP_DOWN` 用于下拉菜单
*/
public $template = self::TEMPLATE_DROP_DOWN;
/**
* @return Filter[]
*/
public function filters(): array
{
return [
//...
];
}
}
此外,您可以在此属性中定义自己的 Blade
模板。
处理 HTTP 参数
为了根据用户提供的 HTTP 参数自动过滤和排序应用程序的数据,包提供了一套强大而灵活的工具。
有效利用这些工具的关键是确保您的模型包含 Filterable
trait 并实现可接受的过滤和排序参数的白名单。
要使您的 App\Models\Post
模型可过滤,请按照以下步骤操作:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Orchid\Filters\Filterable;
use Orchid\Filters\Types\Like;
use Orchid\Filters\Types\Where;
use Orchid\Filters\Types\WhereDate;
use Orchid\Filters\Types\WhereMaxMin;
use Orchid\Filters\Types\WhereDateStartEnd;
class Post extends Model
{
use Filterable;
}
过滤
如前所述,任何过滤操作只能在允许的过滤器列表上执行,该列表使用 allowedFilters
属性作为键值对指定。键表示列的名称,值是处理类。以下是一个示例:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Orchid\Filters\Filterable;
use Orchid\Filters\Types\Like;
use Orchid\Filters\Types\Where;
use Orchid\Filters\Types\WhereDate;
use Orchid\Filters\Types\WhereMaxMin;
use Orchid\Filters\Types\WhereDateStartEnd;
class Post extends Model
{
use Filterable;
/**
* 可以在 URL 中使用过滤器的属性。
*
* @var array
*/
protected $allowedFilters = [
'id' => Where::class,
'user_id' => WhereIn::class,
'rating' => WhereMaxMin::class,
'content' => Like::class,
'publish_at' => WhereDate::class,
'created_at' => WhereDateStartEnd::class,
'deleted_at' => WhereDateStartEnd::class,
];
}
一旦指定了列表,使用自动过滤就很简单。只需调用 filters()
方法,例如:
Post::filters()->paginate();
通过利用这种方法,您可以轻松地将过滤器应用于查询并分页结果。
此代码将自动应用用户 HTTP 请求中包含的任何过滤器或排序规则。
查询示例
为了有效使用此功能,重要的是要对 HTTP 参数如何转换为数据库查询有一个清晰的理解。例如:
http://example.com/demo?filter[id]=1
$model->where('id', '=', 1)
此查询将在模型的 id
列上应用 where
子句,过滤掉不匹配用户提供值的记录。
http://example.com/demo?filter[name]=A
$model->where('name', 'like', '%A%')
此查询将在模型的 name
列上应用 like
子句,搜索名称中包含字母 “A” 的任何记录。
http://example.com/demo?filter[id]=1,2,3,4,5
$model->whereIn('id', [1,2,3,4,5]);
此查询将在模型的 id
列上应用 wherein
子句,过滤匹配指定 ID 的任何记录。
http://example.com/demo?filter[id][min]=1&filter[id][max]=5
$model->whereBetween('id', [1,5]);
此查询将在模型的 id
列上应用 wherebetween
子句,过滤 ID 在 1 和 5 之间的记录。
http://example.com/demo?filter[id][]=1&filter[id][]=2&filter[id][]=3
$model->whereIn('id', [1,2,3]);
此查询将在模型的 id
列上应用 whereIn
子句,过滤 ID 为指定值之一的记录。
http://example.com/demo?filter[rating][min]=1&filter[rating][max]=5
$model->where('rating', '>=', 1)
->where('rating', '<=', 5);
此查询将在模型的 rating
列上应用两个单独的 where
子句,过滤评分在 1 和 5 之间的记录。
http://example.com/demo?filter[rating][min]=1
$model->where('rating', '>=', 1);
此查询将在模型的 rating
列上应用单个 where
子句,过滤评分大于或等于 1 的记录。
http://example.com/demo?filter[publish_at]=2023-02-02
$model->where('publish_at', '2023-02-02')
此查询将在模型的 publish_at
列上应用单个 where
子句,过滤 publish_at
日期恰好等于 2023 年 2 月 2 日的记录。
http://example.com/demo?filter[created_at][start]=2023-01-01&filter[created_at][end]=2023-02-02
$model->whereDate('created_at', '>=', '2023-01-01')
->whereDate('created_at', '<=', '2023-02-02');
此查询将在模型的 created_at
列上应用两个单独的 whereDate
子句,过滤 created_at
日期在指定范围内的记录。
http://example.com/demo?filter[created_at][start]=2023-01-01
$model->whereDate('created_at', '>=', '2023-01-01')
此查询将在模型的 created_at
列上应用单个 whereDate
子句,过滤 created_at
日期大于或等于 2023 年 1 月 1 日的记录。
HTTP 过滤器或排序没有单独的显示模板。您可以在表头中看到此用法的示例。
排序
要启用排序功能,您需要在 allowedSorts
属性中指定列的列表。此列表表示数据库表中可用于排序的列。以下是一个示例:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Orchid\Filters\Filterable;
class Post extends Model
{
use Filterable;
/**
* 可以在 URL 中使用排序的属性。
*
* @var array
*/
protected $allowedSorts = [
'id',
'user_id',
'rating',
'publish_at',
'created_at',
'deleted_at',
];
}
一旦定义了允许排序的列,您可以通过调用 filters()
方法轻松启用排序。此方法将根据提供的 HTTP 参数处理排序。例如:
Post::filters()->paginate();
现在,当您发出 HTTP 请求时,排序行为如下:
http://example.com/demo?sort=created_at
$model->orderBy('created_at', 'asc');
http://example.com/demo?sort=-created_at
$model->orderBy('created_at', 'desc');
默认排序
如果您希望为数据指定默认排序顺序,可以使用 defaultSort
方法。此方法允许您在没有通过 HTTP 请求提供特定排序参数时设置默认排序列。例如:
Post::filters()->defaultSort('id')->paginate();
您还可以指定排序方向作为第二个参数。例如:
Post::filters()->defaultSort('id', 'desc')->paginate();
HTTP 请求的自动排序和过滤不适用于通过关系获取的模型字段。如果需要基于此类字段进行排序或过滤,可以使用第三方包,例如 Eloquent Power Joins。此包可以帮助您解决此问题:
User::orderByPowerJoins('profile.city');
User::orderByPowerJoins('profile.city', 'desc');
然而,您需要手动处理 HTTP 参数 sort
和 filter
,因为包不会自动识别字段名前的 -
符号表示降序排序,以及如何应用过滤器。您可以使用 “过滤器” 来完成此操作。此外,您应该仅使用包方法来基于通过关系访问的字段进行排序或过滤。