data-dog / pager-bundle
symfony2和doctrine orm的分页器包,支持通过过滤器和排序器进行自定义
Requires
- php: >=5.4.0
- doctrine/orm: ~2.3
- symfony/framework-bundle: 2.3 - 5.4
- twig/twig: ~1.34|~2.0|~3.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: ~6.0.0
- sensio/framework-extra-bundle: ^3.0.9
- symfony/symfony: ~3.3.0
README
这个分页器在以下方面有所不同
- 它只有一个通用的类,大约有300行注释代码。其余的源代码都是特定于symfony2框架、twig辅助工具和模板的。
- 它允许创建自定义分页过滤器 - 搜索、选择..并根据特定用例修改数据库查询。
- 它还以传统方式处理排序。
- 它非常小巧,可以经过修改在其他框架中重用。
- 它只能分页Doctrine2 ORM QueryBuilder。为了保持库小巧和向后兼容,不会支持其他内容。如果您需要自定义,请分叉或复制源代码。
- 因为URL查询参数是常数,所以可能每个请求只有一个分页。
演示
要查看功能,最好的方式是查看实际演示。只需克隆包并运行
make
访问http://localhost: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。您可以像其他任何包模板一样进行自定义,例如
- 分页 - app/Resources/DataDogPagerBundle/views/pagination.html.twig
- 搜索过滤器 - app/Resources/DataDogPagerBundle/views/filters/search.html.twig
扩展更多过滤器
最佳的自定义过滤器方法是扩展 twig 扩展或创建一个新的扩展。如果我们提供太多选项,最终可能会让人感到困惑,所以我们添加了一些基本模板。在您的包 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 许可证 授权。