pacolmg/symfony-filter-bundle

用于在Symfony 4实体仓库中过滤对象的轻量级库

安装: 46

依赖: 0

建议者: 0

安全性: 0

星标: 0

关注者: 0

分支: 0

开放问题: 1

类型:symfony-bundle

v1.1.0 2019-12-17 11:20 UTC

This package is auto-updated.

Last update: 2024-09-29 05:45:46 UTC


README

此包为您的Symfony 4应用程序提供了一些方便的过滤和列表创建功能。

许可MIT

安装

通过控制台使用composer添加包

$ composer  require  pacolmg/symfony-filter-bundle

将Bundle添加到config/bundles.php

可能您可以跳过此步骤,因为Symfony Flex会自动完成。但以防万一,请转到文件 config\bundles.php 并检查以下行是否在代码中

...
Pacolmg\SymfonyFilterBundle\PacolmgSymfonyFilterBundle::class => ['all' => true],
...

扩展需要过滤的实体仓库

例如,在一个名为Article的实体中,其仓库应位于src\Repository\ArticleRepository.php

<?php
namespace  App\Repository;

use  Pacolmg\SymfonyFilterBundle\Repository\BaseRepository;
...

class  ArticleRepository  extends  BaseRepository
{
...

现在,安装已完成,Article仓库将拥有新的方法,以便根据不同的字段和不同的方式(如,大于等)查找对象。

可以扩展多个仓库。

使用方法

开始过滤仓库

方法getAll

要从扩展的仓库中过滤对象,应调用仓库的getAll方法

$this->entityManager->getRepository('App:Article')->getAll($filters, $orderBy, $limit, $offset);

参数

  • offset:第一个结果(用于分页)。
  • limit:最大结果数(用于分页)。
  • orderby:它是一个数组,格式如下
    • [字段 => '方向'].
    • 示例:['title' => 'ASC']
    • 因此,结果可以按多个字段排序。
参数$ filter

它是唯一必需的参数,由不同格式的过滤器数组组成

[
    'type' => Constant that defines the behaviour,
    'field' => Field of the Entity (Or fields, separated by pipe ("|")) where search the value,
    'value' => Value to compare
]

**字段可以允许有多个值,这些值由竖线|分隔,以在多个字段中搜索相同的值。

过滤器类型

  • BaseRepository::FILTER_EXACT:比较字段是否等于值。
  • BaseRepository::FILTER_LIKE:比较字段是否类似于值。
  • BaseRepository::FILTER_IN:在值数组中搜索字段。
  • BaseRepository::FILTER_GREATER:比较字段是否大于值。
  • BaseRepository::FILTER_GREATER_EQUAL:比较字段是否大于等于值。
  • BaseRepository::FILTER_LESS:比较字段是否小于值。
  • BaseRepository::FILTER_LESS_EQUAL:比较字段是否小于等于值。
  • BaseRepository::FILTER_DIFFERENT:比较字段是否不等于值。

方法getAllCount

如果需要结果数,则getAllCount方法将返回该数,只需将过滤器传递给该方法即可。

$this->entityManager->getRepository('App:Article')->getAllCount($filters);

示例

因此,在解释了可以使用哪些过滤器之后,如果我们需要包含标题中包含单词tree的文章,我们应该编写以下代码

$data = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'value': 'tree'
    ]
]);

简单吗?那么,现在,我们将查找标题中包含tree且在标题或正文中包含cat的文章

$data = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'value': 'tree'
    ],
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title|body',
        'value': 'cat'
    ]
]);

结果太多?如果需要,我们可以按publishDate排序结果并过滤它们,因为我们只对当前年份感兴趣

$data = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'value': 'tree'
    ],
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title|body',
        'value': 'cat'
    ],
    [
        'type': BaseRepository::FILTER_GREATER_EQUAL,
        'field': 'publishDate',
        'value': date('Y-01-01 00:00')
    ],
    [
        'type': BaseRepository::FILTER_LESS_EQUAL,
        'field': 'publishDate',
        'value': date('Y-31-12 23:59')
    ]
], ['publishDate' => 'DESC']);

结果仍然很多吗?我们应该进行分页,我们想看到第二页,每页显示10个结果

$data = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'value': 'tree'
    ],
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title|body',
        'value': 'cat'
    ],
    [
        'type': BaseRepository::FILTER_GREATER_EQUAL,
        'field': 'publishDate',
        'value': date('Y-01-01 00:00')
    ],
    [
        'type': BaseRepository::FILTER_LESS_EQUAL,
        'field': 'publishDate',
        'value': date('Y-31-12 23:59')
    ]
], ['publishDate' => 'DESC'], 2, 10);

如果您需要在网站上显示结果,您可能需要显示元素的总数,以便进行显示或适当的分页,这很简单

$totalResults = $this->entityManager->getRepository('App:Article')->getAllCount([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'value': 'tree'
    ],
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title|body',
        'value': 'cat'
    ],
    [
        'type': BaseRepository::FILTER_GREATER_EQUAL,
        'field': 'publishDate',
        'value': date('Y-01-01 00:00')
    ],
    [
        'type': BaseRepository::FILTER_LESS_EQUAL,
        'field': 'publishDate',
        'value': date('Y-31-12 23:59')
    ]
]);

方法 getDistinctField

可能需要字段的不同值来过滤选择,请以字段名称作为参数调用此函数。

$this->entityManager->getRepository('App:Article')->getAllCount($field);

示例

我们需要将实体的所有不同作者放入选择中

$authors = $this->entityManager->getRepository('App:Article')->getAllCount('author');

使用服务进行过滤

该包提供了一个服务:Pacolmg\SymfonyFilterBundle\Service\FilterService;

在此服务中,将仓库的 getAllgetAllCount 方法合并,因此服务中的 getFiltered 方法将返回仓库的对象集合和元素总数,以帮助控制器和视图进行分页。

排序参数具有不同的格式,以便传递字段和方向,避免编写数组。

$this->filterService->getFiltered(
	$repository,
	$filters,
	$page,
	$limit,
	$sortBy,
	$sortDir	
);

示例

以下示例,从服务或控制器进行编码的最后一步

$this->filterService->getFiltered(
	$this->entityManager->getRepository('App:Article'),
	[
	    [
	        'type': BaseRepository::FILTER_LIKE,
	        'field': 'title',
	        'value': 'tree'
	    ],
	    [
	        'type': BaseRepository::FILTER_LIKE,
	        'field': 'title|body',
	        'value': 'cat'
	    ],
	    [
	        'type': BaseRepository::FILTER_GREATER_EQUAL,
	        'field': 'publishDate',
	        'value': date('Y-01-01 00:00')
	    ],
	    [
	        'type': BaseRepository::FILTER_LESS_EQUAL,
	        'field': 'publishDate',
	        'value': date('Y-31-12 23:59')
	    ]
	],
	2,
	10,
	'publishDate',
	'DESC'	
);

此示例将返回一个包含两个键的数组

[
	'data' => colection of objects,
	'total' => Total number of elements filtered by $filters
]

从控制器进行过滤

为了与网站完全集成,该包还提供了一个其他服务 Pacolmg\SymfonyFilterBundle\Service\ExternalParametersService,其中包含一些从 Request 获取参数的方法。

获取页面和限制

getPageAndLimit 方法以数组形式返回页面和每页元素数。它从参数 pagelimit 获取信息。

示例

在控制器中,我们可以这样编写,变量 $page$limit 将具有页面和每页元素数,最小页面为 1,最大限制为 500。

list($page, $limit) = $this->externalParametersService->getPageAndLimit($request);

获取过滤器

getFilters 方法需要 $request$filters,并将返回它们的值。为了使其工作,我们需要为每个过滤器添加一对字段

[
    'type' => Constant that defines the behaviour,
    'field' => Field of the Entity (Or fields separated by pipe ("|")) where find the value,
    'request_type' => Type of the value
    'request_name' => Name of the parameter
]

请求类型

request_type 的类型可以是

  • int
  • string (默认)
  • bool
  • array
  • date

示例

我们有一个带搜索输入的网站,该输入将参数 t 的值发送到控制器,我们想使用这个参数来查找类似于参数 t 的标题

http://mywebsite.com?t=tree

在控制器中,我们应该这样编写

$filters = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'request_type': 'string',
        'request_name': 't'
    ]
]);

list($data, $totalData) = $this->filterService->getFiltered($filters);

在下一个示例中,我们有一些分页参数

http://mywebsite.com?t=tree&page=2&limit=10

因此,控制器中的代码将是这样的

list($page, $limit) = $this->externalParametersService->getPageAndLimit($request);

$filters = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'request_type': 'string',
        'request_name': 't'
    ]
]);

list($data, $totalData) = $this->filterService->getFiltered($filters, $page, $limit);

从视图进行过滤

该包还希望帮助您在视图中使用表单,因此您可以包含一些预定义的字段,或者扩展您完整的表单 "@PacolmgSymfonyFilter/filters/layout.html.twig"

###输入预定义的字段

  • 文本输入: @PacolmgSymfonyFilter/filters/input.html.twig
  • 数字输入: @PacolmgSymfonyFilter/filters/number.html.twig
  • 日期时间本地输入 (仅在chrome中工作): @PacolmgSymfonyFilter/filters/date.html.twig
  • 选择: @PacolmgSymfonyFilter/filters/select.html.twig
参数

每个输入都有一些常见的参数

  • name (string,必需):输入的属性名称。
  • id (string,非必需):输入的id。如果没有定义,则id为:symfony_filter_form_+name
  • class (string,非必需):输入的类。如果没有定义,则类为 form-control
  • placeholder (string,非必需):输入的占位符。
  • print_label (boolean,非必需):是否打印字段的标签。
  • label (string,非必需):字段的标签。如果没有定义且 print_label 为 true,则标签为占位符。标签可以是 HTML。
  • defaultData (string|array|int,非必需):字段的默认值。
  • attrs (array):输入的可选属性。

选择字段类型将有两个其他参数,其中一个是必需的

  • options (array,必需):选项数组
    • 数组选项的格式为:[值 => 文本, 值 => 文本, ...]
  • multiple布尔值,非必须):是否为多选。默认为False。

示例

我们仍然想找到标题包含特定单词的文章,这个单词将从视图中的输入收集。我们还希望按日期和状态过滤它们,因此表单的一个例子可能是

{% raw %}
{% extends "@PacolmgSymfonyFilter/layout.html.twig" %}
{% block pacolmg_symfony_filter_bundle_form_filters %}
    <div class="col-sm-2">
        {{ include('@PacolmgSymfonyFilter/filters/text.html.twig', {placeholder: 'Title', name: 't'}, with_context = false) }}
    </div>
    <div class="col-sm-2">
        {{ include('@PacolmgSymfonyFilter/filters/date.html.twig', {placeholder: 'From', name: 'from'}, with_context = false) }}
    </div>
    <div class="col-sm-2">
        {{ include('@PacolmgSymfonyFilter/filters/date.html.twig', {placeholder: 'To', name: 'to'}, with_context = false) }}
    </div>
    <div class="col-sm-2">
        {{ include('@PacolmgSymfonyFilter/filters/select.html.twig', {placeholder: 'status', name: 's', options: {'1':'Created', '2':'Published', '3':'Deleted'} }, with_context = false) }}
    </div>
{% endblock %}
{% endraw %}

这个表单将只传递参数,以便在编码时捕捉它们

$filters = $this->entityManager->getRepository('App:Article')->getAll([
    [
        'type': BaseRepository::FILTER_LIKE,
        'field': 'title',
        'request_type': 'string',
        'request_name': 't'
    ],
    [
        'type': BaseRepository::FILTER_GREATER_EQUAL,
        'field': 'publishedAt',
        'request_type': 'date',
        'request_name': 'from'
    ],
    [
        'type': BaseRepository::FILTER_LESS_EQUAL,
        'field': 'publishedAt',
        'request_type': 'date',
        'request_name': 'to'
    ],
    [
        'type': BaseRepository::FILTER_EXACT,
         'field': 'status',
         'request_type': 'int',
         'request_name': 's'
    ]
]);

list($data, $totalData) = $this->filterService->getFiltered($filters);

想象一下,你改变了主意,更愿意获取可以发布或创建的文章,因此我们需要将状态选择转换为多选

...
<div class="col-sm-2">
        {% raw %}
        {{ include('@PacolmgSymfonyFilter/filters/select.html.twig', {placeholder: 'status', name: 's', options: {'1':'Created', '2':'Published', '3':'Deleted'} }, with_context = false) }}
        {% endraw %}
</div>
...

然后在控制器中,更改过滤器的类型

...
    [
        'type': BaseRepository::FILTER_IN,
         'field': 'status',
         'request_type': 'int',
         'request_name': 's'
    ]
...

分页

因此,在控制器、服务和仓库中,可以通过分页获取结果。该捆绑包还提供了一个twig,使分页开发变得简单。只需包含 '@PacolmgSymfonyFilter/components/pagination.html.twig' 视图,即可查看页面。

参数

必填参数包括

  • nbPages整数,必填):总页数。
  • currentPage整数,必填):当前页。
  • url字符串,必填):用于分页重定向的symfony路由。
  • params数组,必填):路由需要工作的参数(id,q,...)。

twig还有一些可选参数

  • nearbyPagesLimit整数,非必须):当前页周围的页面数。
    • 默认值为4。
  • align字符串,非必须):值必须是: "end", "center" 或 "start"(基于bootstrap flex)。
    • 默认值为 "end"。
  • classPageItem字符串,非必须):"li"标签的类。
    • 默认值为 "page-item"。
  • classPageLink字符串,非必须):链接的类。
    • 默认值为 "page-link"。
  • classDisabled字符串,非必须):禁用页面的类。
    • 默认值为 "disabled"。
  • classActive字符串,非必须):当前页的类。
    • 默认值为 "active"。

示例

我们有自己的文章索引页面,其中包含前面示例中定义的过滤器,现在我们想显示页数

为了避免在twig中过多逻辑,我们在控制器中构建参数

list($page, $limit) = $this->externalParametersService->getPageAndLimit($request);

$filters = $this->entityManager->getRepository('App:Article')->getAll([
    ...
]);

list($data, $totalData) = $this->filterService->getFiltered($filters);

$paginationData = [
            'nbPages' => ceil($data['total'] / $limit),
            'currentPage' => $page,
            'url' => $request->get('_route'),
            'params' => $request->query->all()
        ];

在视图中

{% raw %}
{{ include('@PacolmgSymfonyFilter/components/pagination.html.twig', paginationData, with_context = false) }}
{% endraw %}

希望这个捆绑包的过滤和分页你的实体不再痛苦。