granedirval / data-dog-pager-bundle
symfony2 和 doctrine orm 的分页器包,支持通过过滤器排序器进行自定义
Requires
- php: >=5.4.0
- doctrine/orm: ~2.3
- symfony/framework-bundle: 2.3 - 4.0
- twig/twig: ~1.5|~2.0
Requires (Dev)
- ext-pdo: *
- ext-pdo_sqlite: *
- doctrine/doctrine-bundle: ^1.6
- doctrine/doctrine-fixtures-bundle: ^2.3
- doctrine/orm: ~2.5.0
- fzaninotto/faker: ~1.5
- phpunit/phpunit: ~4.7.0
- sensio/framework-extra-bundle: ^3.0.9
- symfony/symfony: ~3.0.0
README
这个分页器在以下方面有所不同
- 它只有一个包含大约300行注释代码的通用类。其余的源代码都是针对 symfony2 框架、twig 辅助函数和模板的。
- 它允许创建自定义分页过滤器 - 搜索、选择等,并根据特定用例修改数据库查询。
- 它还以传统方式处理排序。
- 它非常小巧,可以在其他框架中重复使用,只需进行必要的修改。
- 它只能分页 Doctrine2 ORM QueryBuilder。为了保持库小巧和向后兼容,不会支持其他任何内容。对于您的自定义修改,请克隆或复制源代码。
- 每个请求可能只有一个分页,因为 URL 查询参数是恒定的。
演示
要查看功能,最好的方式是查看实际演示。只需克隆包并运行
make
访问 https://:8000 查看带有自定义过滤器和排序器的分页假项目。
演示应用程序的源代码位于 example 目录中,它是一个基本的 symfony 应用程序。
安装
首先,使用 composer 安装它
composer require data-dog/pager-bundle
然后,在您的 AppKernel 包中添加它。
使用方法
在您的控制器中的一般使用示例
<?php namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\QueryBuilder; use DataDog\PagerBundle\Pagination; class ProjectController extends Controller { /** * @Method("GET") * @Template * @Route("/", name="homepage") */ public function indexAction(Request $request) { $qb = $this->getDoctrine()->getManager()->getRepository("AppBundle:Project") ->createQueryBuilder('p') ->addSelect('l') ->innerJoin('p.language', 'l'); $projects = new Pagination($qb, $request); return compact('projects'); } }
您需要使用 doctrine 查询构建器 和请求来构建分页。分页对象就像一个数组,因此您可以将其传递到视图中并迭代分页项。
视图
<table class="table table-hover"> <thead> <tr> <th>#</th> <th>{{ sorter_link(projects, "p.code", "Code") }}</th> <th>{{ sorter_link(projects, "p.name", "Name") }}</th> <th>{{ sorter_link(projects, "p.hoursSpent", "Hours Spent") }}</th> <th>{{ sorter_link(projects, "l.code", "Language") }}</th> </tr> </thead> <tbody> {% for project in projects %} <tr> <td>{{ project.id }}</td> <td>{{ project.code }}</td> <td>{{ project.name }}</td> {% if project.isOverDeadline %} <td class="text-danger">{{ project.hoursSpent }}</td> {% else %} <td class="text-success">{{ project.hoursSpent }}</td> {% endif %} <td>{{ project.language.code }}</td> </tr> {% endfor %} </tbody> </table> <div class="panel-footer"> {{ pagination(projects) }} </div>
使用了 twig 辅助函数
- sorter_link - 使用 twig 模板生成带有排序顺序类等的链接。
- pagination - 创建用于导航页面的分页 HTML 代码。
这些模板可以通过标准的 symfony 方式进行修改,请参阅配置部分。
过滤器
为了以不同方式过滤分页结果,您可以扩展代码。在控制器中提供一些分页选项。
<?php namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\QueryBuilder; use DataDog\PagerBundle\Pagination; class ProjectController extends Controller { /** * Our filter handler function, which allows us to * modify the query builder specifically for our filter option */ public function projectFilters(QueryBuilder $qb, $key, $val) { switch ($key) { case 'p.name': if ($val) { $qb->andWhere($qb->expr()->like('p.name', ':name')); $qb->setParameter('name', "%$val%"); } break; case 'p.hoursSpent': switch ($val) { case 'lessThan10': $qb->andWhere($qb->expr()->lt('p.hoursSpent', 10)); break; case 'upTo20': $qb->andWhere($qb->expr()->lte('p.hoursSpent', 20)); break; case 'moreThan2weeks': $qb->andWhere($qb->expr()->gte('p.hoursSpent', 80)); break; case 'overDeadline': $qb->andWhere($qb->expr()->gt('p.hoursSpent', 'p.deadline')); break; } break; case 'l.code': $qb->andWhere($qb->expr()->eq('l.code', ':code')); $qb->setParameter('code', $val); break; default: // Do not allow filtering by anything else throw new \Exception("filter not allowed"); // You can also enable automatic filtering //$paramName = preg_replace('/[^A-z]/', '_', $key); //$qb->andWhere($qb->expr()->eq($key, ":$paramName")); //$qb->setParameter($paramName, $val); } } /** * @Method("GET") * @Template * @Route("/", name="homepage") */ public function indexAction(Request $request) { $qb = $this->getDoctrine()->getManager()->getRepository("AppBundle:Project") ->createQueryBuilder('p') ->addSelect('l') ->innerJoin('p.language', 'l'); $options = [ 'sorters' => ['l.code' => 'ASC'], // sorted by language code by default 'filters' => ['p.hoursSpent' => 'overDeadline'], // we can apply a filter option by default 'applyFilter' => [$this, 'projectFilters'], // custom filter handling ]; // our language filter options, the key will be used in where statemt by default // and the value as title. // The $filterAny key is a placeholder to skip the filter, so the any value could be ok. $languages = [ Pagination::$filterAny => 'Any', 'php' => 'PHP', 'hs' => 'Haskell', 'go' => 'Golang', ]; // our spent time filter options, has specific keys so we know how to customize $spentTimeGroups = [ Pagination::$filterAny => 'Any', 'lessThan10' => 'Less than 10h', 'upTo20' => 'Up to 20h', 'moreThan2weeks' => 'More than 2weeks', 'overDeadline' => 'Over deadline', ]; $projects = new Pagination($qb, $request, $options); return compact('projects', 'languages', 'spentTimeGroups'); } }
现在我们添加了三个过滤器
$languages
和 $spentTimeGroups
将用作 filter_select
选项。语言选项很简单,它们引用直接值,因此不需要修改 where 语句。但是花费时间组是自定义的,所以我们使用自定义选项。在这种情况下,我们需要将 applyFilter
选项设置为可调用,以便根据我们的自定义选项相应地修改 QueryBuilder。
注意:如果您管理自定义过滤,请确保使用参数或使用 $qb->expr()->literal("string")
以防止 SQL 注入。如果您有自定义过滤器处理程序,您必须管理所有您的过滤器,默认处理程序将不会激活。
那么视图是如何改变的
<table class="table table-hover"> <thead> <tr> <th>#</th> <th>{{ sorter_link(projects, "p.code", "Code") }}</th> <th>{{ sorter_link(projects, "p.name", "Name") }}</th> <th>{{ sorter_link(projects, "p.hoursSpent", "Hours Spent") }}</th> <th>{{ sorter_link(projects, "l.code", "Language") }}</th> </tr> <tr role="row" class="filter"> <td></td> <td></td> <td>{{ filter_search(projects, "p.name") }}</td> <td>{{ filter_select(projects, "p.hoursSpent", spentTimeGroups) }}</td> <td>{{ filter_select(projects, "l.code", languages) }}</td> </tr> </thead> <tbody> {% for project in projects %} <tr> <td>{{ project.id }}</td> <td>{{ project.code }}</td> <td>{{ project.name }}</td> {% if project.isOverDeadline %} <td class="text-danger">{{ project.hoursSpent }}</td> {% else %} <td class="text-success">{{ project.hoursSpent }}</td> {% endif %} <td>{{ project.language.code }}</td> </tr> {% endfor %} </tbody> </table> <div class="panel-footer"> {{ pagination(projects) }} </div>
我们使用了两个新的 twig 函数来处理过滤器
- filter_search - 用于按名称搜索项目。
- filter_select - 用于基本选项过滤器。
这些函数用于渲染我们过滤器的twig模板。
链接
如果您需要创建一个链接并保持搜索过滤器和排序器的应用,请使用$pagination->query()
函数获取所有必要的URL参数,并将其与您的链接参数合并。
示例示例在单独的控制器操作中处理项目的启用和禁用切换,并保持所有分页属性。
配置
一般使用不需要配置。但为了自定义分页,可能需要在app.php
中设置全局选项,例如。
<?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Debug\Debug; use DataDog\PagerBundle\Pagination; $loader = require_once __DIR__.'/../app/autoload.php'; Debug::enable(); Pagination::$defaults = array_merge(Pagination::$defaults, [ 'limit' => 15, 'range' => 9, ]); Pagination::$maxPerPage = 200; require_once __DIR__.'/../app/AppKernel.php'; $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);
模板
过滤器和分页的默认模板基于twitter bootstrap和fontawesome。您可以像其他任何bundle模板一样自定义它们,例如
- 分页 - app/Resources/DataDogPagerBundle/views/pagination.html.twig
- 搜索过滤器 - app/Resources/DataDogPagerBundle/views/filters/search.html.twig
添加更多过滤器以扩展
自定义过滤器的最佳方式是扩展twig扩展或创建一个新的扩展。如果我们提供许多选项,最终会让人困惑,所以我们添加了一些基本模板。在您的bundle services.yml
中更新参数
parameters: datadog.pager.twig_extension.class: AppBundle\Twig\PaginationExtension
然后创建一个类
<?php namespace AppBundle\Twig; use DataDog\PagerBundle\Twig\PaginationExtension as Base; use DataDog\PagerBundle\Pagination; class PaginationExtension extends Base { /** * {@inheritdoc} */ public function getFunctions() { $defaults = [ 'is_safe' => ['html'], 'needs_environment' => true, ]; $funcs = parent::getFunctions(); $funcs['filter_search_placeholder'] = new \Twig_Function_Method($this, 'filterSearchPlaceholder', $defaults); return $funcs; } public function filterSearchPlaceholder(\Twig_Environment $twig, Pagination $pagination, $key, $placeholder) { $value = isset($pagination->query()['filters'][$key]) ? $pagination->query()['filters'][$key] : ''; return $twig->render('AppBundle::filters/search_placeholder.html.twig', compact('key', 'pagination', 'value', 'placeholder')); } }
最后,根据您的需求复制并修改模板
截图
许可协议
分页器可以免费使用,并使用MIT许可协议