diff --git a/DependencyInjection/ChillMainExtension.php b/DependencyInjection/ChillMainExtension.php
index 9d900a32c..ef3fed0ae 100644
--- a/DependencyInjection/ChillMainExtension.php
+++ b/DependencyInjection/ChillMainExtension.php
@@ -31,11 +31,15 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface
$container->setParameter('chill_main.routing.resources',
$config['routing']['resources']);
+
+ $container->setParameter('chill_main.pagination.item_per_page',
+ $config['pagination']['item_per_page']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$loader->load('services/logger.yml');
$loader->load('services/repositories.yml');
+ $loader->load('services/pagination.yml');
}
public function prepend(ContainerBuilder $container)
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index cb8ba9982..8bb6c9805 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -35,7 +35,17 @@ class Configuration implements ConfigurationInterface
->arrayNode('resources')
->prototype('scalar')->end()
->end()
+ ->end()
->end()
+ ->arrayNode('pagination')
+ ->canBeDisabled()
+ ->children()
+ ->integerNode('item_per_page')
+ ->info('The number of item to show in the page result, by default')
+ ->min(1)
+ ->defaultValue(50)
+ ->end()
+ ->end()
->end()
->end();
diff --git a/Pagination/ChillPaginationTwig.php b/Pagination/ChillPaginationTwig.php
new file mode 100644
index 000000000..ef36685b4
--- /dev/null
+++ b/Pagination/ChillPaginationTwig.php
@@ -0,0 +1,76 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+/**
+ * add twig function to render pagination
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class ChillPaginationTwig extends \Twig_Extension
+{
+ const LONG_TEMPLATE = 'ChillMainBundle:Pagination:long.html.twig';
+ const SHORT_TEMPLATE = 'ChillMainBundle:Pagination:short.html.twig';
+
+ public function getName()
+ {
+ return 'chill_pagination';
+ }
+
+ public function getFunctions()
+ {
+ return array(
+ new \Twig_SimpleFunction(
+ 'chill_pagination',
+ array($this, 'paginationRender'),
+ array(
+ 'needs_environment' => true,
+ 'is_safe' => ['html']
+ )
+ )
+ );
+ }
+
+ public function paginationRender(
+ \Twig_Environment $env,
+ PaginatorInterface $paginator,
+ $template = 'ChillMainBundle:Pagination:long.html.twig'
+ ) {
+ switch ($template) {
+ case 'long':
+ $t = self::LONG_TEMPLATE;
+ break;
+ case 'short':
+ $t = self::SHORT_TEMPLATE;
+ break;
+ default:
+ $t = $template;
+ }
+
+ return $env->render($t, array(
+ 'paginator' => $paginator,
+ 'current' => $paginator->getCurrentPage()->getNumber()
+ ));
+ }
+}
diff --git a/Pagination/Page.php b/Pagination/Page.php
new file mode 100644
index 000000000..2cf400e4e
--- /dev/null
+++ b/Pagination/Page.php
@@ -0,0 +1,102 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+/**
+ * a page is an element of a pagination
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class Page implements PageInterface
+{
+ /**
+ *
+ * @var UrlGeneratorInterface
+ */
+ protected $urlGenerator;
+
+ /**
+ * the number of the current page
+ *
+ * @var int
+ */
+ protected $number;
+
+ /**
+ * The route for the current page
+ *
+ * @var string
+ */
+ protected $route;
+
+ /**
+ * Parameters for the route to the current page
+ *
+ * @var array
+ */
+ protected $routeParameters;
+
+ /**
+ * the number of item per page
+ *
+ * @var int
+ */
+ protected $itemPerPage;
+
+
+ public function __construct(
+ $number,
+ $itemPerPage,
+ UrlGeneratorInterface $urlGenerator,
+ $route,
+ array $routeParameters
+ ) {
+ $this->urlGenerator = $urlGenerator;
+ $this->number = $number;
+ $this->itemPerPage = $itemPerPage;
+ $this->route = $route;
+ $this->routeParameters = $routeParameters;
+ }
+
+ public function generateUrl()
+ {
+ return $this->urlGenerator->generate($this->route, $this->routeParameters);
+ }
+
+ public function getFirstItemNumber()
+ {
+ return ($this->number - 1) * $this->itemPerPage;
+ }
+
+ public function getLastItemNumber()
+ {
+ return $this->number * $this->itemPerPage - 1;
+ }
+
+ public function getNumber()
+ {
+ return $this->number;
+ }
+
+}
diff --git a/Pagination/PageGenerator.php b/Pagination/PageGenerator.php
new file mode 100644
index 000000000..26add87fa
--- /dev/null
+++ b/Pagination/PageGenerator.php
@@ -0,0 +1,73 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+/**
+ * PageGenerator associated with a Paginator
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class PageGenerator implements \Iterator
+{
+ /**
+ *
+ * @var Paginator
+ */
+ protected $paginator;
+
+ /**
+ *
+ * @var int
+ */
+ protected $current = 1;
+
+ public function __construct(Paginator $paginator)
+ {
+ $this->paginator = $paginator;;
+ }
+
+ public function current()
+ {
+ return $this->paginator->getPage($current);
+ }
+
+ public function key()
+ {
+ return $this->current;
+ }
+
+ public function next()
+ {
+ $this->current++;
+ }
+
+ public function rewind()
+ {
+ $this->current = 1;
+ }
+
+ public function valid()
+ {
+ return $this->current > 0
+ && $this->current <= $this->paginator->countPages();
+ }
+}
diff --git a/Pagination/PageInterface.php b/Pagination/PageInterface.php
new file mode 100644
index 000000000..aa87c289c
--- /dev/null
+++ b/Pagination/PageInterface.php
@@ -0,0 +1,43 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+/**
+ * Represents a page included in a pagination
+ *
+ * @author Julien Fastré
+ */
+interface PageInterface
+{
+ public function generateUrl();
+
+ /**
+ * get the page number.
+ *
+ * The first page number is 1.
+ */
+ public function getNumber();
+
+ public function getFirstItemNumber();
+
+ public function getLastItemNumber();
+
+}
diff --git a/Pagination/Paginator.php b/Pagination/Paginator.php
new file mode 100644
index 000000000..037fa5232
--- /dev/null
+++ b/Pagination/Paginator.php
@@ -0,0 +1,246 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+
+/**
+ * Standard paginator class.
+ *
+ * Represent a set of paginated pages;
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class Paginator implements PaginatorInterface
+{
+ /**
+ * The number of total items
+ *
+ * @var int
+ */
+ protected $totalItems;
+
+ /**
+ * the number of items on a single page
+ *
+ * @var int
+ */
+ protected $itemPerPage;
+ /**
+ * The number of the current page
+ *
+ * @var int
+ */
+ protected $currentPageNumber;
+
+ /**
+ * the route of the pages
+ *
+ * @var string
+ */
+ protected $route;
+
+ /**
+ * the parameters of the route
+ *
+ * @var string[]
+ */
+ protected $routeParameters;
+
+ /**
+ * the generator for url
+ *
+ * @var UrlGeneratorInterface
+ */
+ protected $urlGenerator;
+
+ /**
+ * the key in the GET parameter to indicate the page number in
+ * generated routes
+ *
+ * @var string
+ */
+ protected $pageKey;
+
+ /**
+ * the key in the GET parameter to indicate the number of item per page
+ *
+ * @var string
+ */
+ protected $itemPerPageKey;
+
+
+ public function __construct(
+ $totalItems,
+ $itemPerPage,
+ $currentPageNumber,
+ $route,
+ array $routeParameters,
+ UrlGeneratorInterface $urlGenerator,
+ $pageKey,
+ $itemPerPageKey
+ ) {
+ $this->totalItems = $totalItems;
+ $this->itemPerPage = $itemPerPage;
+ $this->currentPageNumber = $currentPageNumber;
+ $this->route = $route;
+ $this->routeParameters = $routeParameters;
+ $this->urlGenerator = $urlGenerator;
+ $this->pageKey = $pageKey;
+ $this->itemPerPageKey = $itemPerPageKey;
+ }
+
+ public function count()
+ {
+ return $this->countPages();
+ }
+
+ /**
+ *
+ * @return \Chill\MainBundle\Pagination\Page
+ */
+ public function getCurrentPage()
+ {
+ return $this->getPage($this->currentPageNumber);
+ }
+
+ public function getCurrentPageFirstItemNumber()
+ {
+ return $this->getCurrentPage()->getFirstItemNumber();
+ }
+
+ public function isCurrentPage(PageInterface $page)
+ {
+ return $page->getNumber() === $this->currentPageNumber;
+ }
+
+ public function getItemPerPage()
+ {
+ return $this->itemPerPage;
+ }
+
+ public function setItemPerPage($itemPerPage)
+ {
+ $this->itemPerPage = $itemPerPage;
+ }
+
+ public function getTotalItems()
+ {
+ return $this->totalItems;
+ }
+
+ public function countPages()
+ {
+ $nb = floor($this->totalItems / $this->itemPerPage);
+
+ if ($this->totalItems % $this->itemPerPage > 0) {
+ $nb++;
+ }
+
+ return $nb == 0 ? 1 : (int) $nb;
+ }
+
+ /**
+ *
+ * @return \Chill\MainBundle\Pagination\Page
+ * @throws \RuntimeException if the next page does not exists
+ */
+ public function getNextPage()
+ {
+ if (!$this->hasNextPage()) {
+ throw new \RuntimeException("this page has no next page");
+ }
+
+ return $this->getPage($this->currentPageNumber + 1);
+ }
+
+ /**
+ *
+ * @return \Chill\MainBundle\Pagination\Page
+ * @throws \RuntimeException if the next page does not exists
+ */
+ public function getPreviousPage()
+ {
+ if (!$this->hasPreviousPage()) {
+ throw new \RuntimeException("this page has no previous page");
+ }
+
+ return $this->getPage($this->currentPageNumber - 1);
+ }
+
+ /**
+ *
+ * @return bool
+ */
+ public function hasNextPage()
+ {
+ return $this->hasPage($this->currentPageNumber + 1);
+ }
+
+ /**
+ *
+ * @return bool
+ */
+ public function hasPreviousPage()
+ {
+ return $this->hasPage($this->currentPageNumber - 1);
+ }
+
+ public function hasPage($number)
+ {
+ return $number > 0 and
+ $number <= $this->countPages();
+ }
+
+
+ /**
+ *
+ * @param type $number
+ * @return \Chill\MainBundle\Pagination\Page
+ */
+ public function getPage($number) {
+ if (!$this->hasPage($number)) {
+ throw new \RuntimeException("The page with number $number does not "
+ . "exists");
+ }
+
+ return new Page(
+ $number,
+ $this->itemPerPage,
+ $this->urlGenerator,
+ $this->route,
+ array_merge($this->routeParameters, array(
+ $this->pageKey => $number,
+ $this->itemPerPageKey => $this->itemPerPage
+ ))
+ );
+ }
+
+ public function getPagesGenerator()
+ {
+ for ($i = 1; $i <= $this->countPages(); $i++) {
+ yield $this->getPage($i);
+ }
+ }
+
+}
diff --git a/Pagination/PaginatorFactory.php b/Pagination/PaginatorFactory.php
new file mode 100644
index 000000000..d35449a48
--- /dev/null
+++ b/Pagination/PaginatorFactory.php
@@ -0,0 +1,140 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Create paginator instances
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class PaginatorFactory
+{
+ /**
+ * the default item per page. This may be overriden by
+ * the request or inside the paginator.
+ *
+ * @var int
+ */
+ private $itemPerPage;
+
+ /**
+ * the router and generator for url
+ *
+ * @var RouterInterface
+ */
+ private $router;
+
+ /**
+ * the request stack
+ *
+ * @var RequestStack
+ */
+ private $requestStack;
+
+ const DEFAULT_CURRENT_PAGE_KEY = 'page';
+ const DEFAULT_ITEM_PER_NUMBER_KEY = 'item_per_page';
+ const DEFAULT_PAGE_NUMBER = 1;
+
+
+ public function __construct(
+ RequestStack $requestStack,
+ RouterInterface $router,
+ $itemPerPage = 50
+ ) {
+ $this->itemPerPage = $itemPerPage;
+ $this->requestStack = $requestStack;
+ $this->router = $router;
+ }
+
+ /**
+ * create a paginator instance
+ *
+ * The default route and route parameters are the current ones. If set,
+ * thos route are overriden.
+ *
+ * @param int $totalItems
+ * @param string|null $route the specific route to use in pages
+ * @param array|null $routeParameters the specific route parameters to use in pages
+ * @return PaginatorInterface
+ */
+ public function create(
+ $totalItems,
+ $route = null,
+ array $routeParameters = null
+ ) {
+
+ return new Paginator(
+ $totalItems,
+ $this->getCurrentItemPerPage(),
+ $this->getCurrentPageNumber(),
+ $route === null ? $this->getCurrentRoute() : $route,
+ $routeParameters === null ? $this->getCurrentRouteParameters() :
+ $routeParameters,
+ $this->router,
+ self::DEFAULT_CURRENT_PAGE_KEY,
+ self::DEFAULT_ITEM_PER_NUMBER_KEY);
+ }
+
+ /**
+ *
+ * @return int
+ */
+ public function getCurrentPageNumber()
+ {
+ return $this->requestStack
+ ->getCurrentRequest()
+ ->query
+ ->getInt(self::DEFAULT_CURRENT_PAGE_KEY, self::DEFAULT_PAGE_NUMBER);
+ }
+
+ public function getCurrentItemPerPage()
+ {
+ return $this->requestStack
+ ->getCurrentRequest()
+ ->query
+ ->getInt(self::DEFAULT_ITEM_PER_NUMBER_KEY, $this->itemPerPage);
+ }
+
+ public function getCurrentPageFirstItemNumber()
+ {
+ return ($this->getCurrentPageNumber() - 1) *
+ $this->getCurrentItemPerPage();
+ }
+
+ protected function getCurrentRoute()
+ {
+ $request = $this->requestStack->getCurrentRequest();
+
+ return $request->get('_route');
+ }
+
+ protected function getCurrentRouteParameters()
+ {
+ return array_merge(
+ $this->router->getContext()->getParameters(),
+ $this->requestStack->getCurrentRequest()
+ ->query->all());
+ }
+}
diff --git a/Pagination/PaginatorInterface.php b/Pagination/PaginatorInterface.php
new file mode 100644
index 000000000..8023a8d34
--- /dev/null
+++ b/Pagination/PaginatorInterface.php
@@ -0,0 +1,130 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Pagination;
+
+/**
+ * Represent a set of numbered pages
+ *
+ * Allow to calculate and render pagination for a set of pages.
+ *
+ * The items are elements that `could` be shown. The item are divided and shown
+ * into pages. Each page is numbered and count a given number of item per page.
+ *
+ * The first page number is 1, although the first result number is 0.
+ *
+ * @author Julien Fastré
+ */
+interface PaginatorInterface extends \Countable
+{
+ /**
+ * get the number of result for this pagination
+ *
+ * @return int
+ */
+ public function getTotalItems();
+
+ /**
+ * get the first result for the current page
+ *
+ * @return int
+ */
+ public function getCurrentPageFirstItemNumber();
+
+ public function getItemPerPage();
+
+ public function setItemPerPage($itemPerPage);
+
+ /**
+ * get the number of page for this pagination.
+ *
+ * @return int
+ */
+ public function countPages();
+
+ /**
+ * get the current page
+ *
+ * @return PageInterface
+ */
+ public function getCurrentPage();
+
+ /**
+ * check if the given page is the current page
+ *
+ * @param \Chill\MainBundle\Pagination\PageInterface $page
+ * @return bool
+ */
+ public function isCurrentPage(PageInterface $page);
+
+ /**
+ * check if the page with the given number exists
+ *
+ * @param int $number
+ */
+ public function hasPage($number);
+
+ /**
+ * get page by his number
+ *
+ * @param int $number
+ * @throws \RuntimeException if the pagination has no page with specified number
+ */
+ public function getPage($number);
+
+ /**
+ * get the next page
+ *
+ * @return PageInterface
+ * @throws \RuntimeException if the pagination has not next page
+ */
+ public function getNextPage();
+
+ /**
+ * get the previous page
+ *
+ * @return PageInterface
+ * @throws \RuntimeException if the pagination has not previous page
+ */
+ public function getPreviousPage();
+
+ /**
+ * check if the current page has a next page
+ *
+ * @return bool
+ */
+ public function hasNextPage();
+
+ /**
+ * check if the current page has a page before
+ *
+ * @return bool
+ */
+ public function hasPreviousPage();
+
+ /**
+ * get a generator to generate pages
+ *
+ * @return \Generator which return PageInterface elements
+ */
+ public function getPagesGenerator();
+
+
+}
diff --git a/Resources/config/services/pagination.yml b/Resources/config/services/pagination.yml
new file mode 100644
index 000000000..848599f42
--- /dev/null
+++ b/Resources/config/services/pagination.yml
@@ -0,0 +1,12 @@
+services:
+ chill_main.paginator_factory:
+ class: Chill\MainBundle\Pagination\PaginatorFactory
+ arguments:
+ - "@request_stack"
+ - "@router"
+ - "%chill_main.pagination.item_per_page%"
+
+ chill_main.paginator.twig_extensions:
+ class: Chill\MainBundle\Pagination\ChillPaginationTwig
+ tags:
+ - { name: twig.extension }
diff --git a/Resources/views/Pagination/long.html.twig b/Resources/views/Pagination/long.html.twig
new file mode 100644
index 000000000..3166c187b
--- /dev/null
+++ b/Resources/views/Pagination/long.html.twig
@@ -0,0 +1,27 @@
+{%- macro page(text, page, class = "") -%}
+{{ text }}
+{%- endmacro -%}
+
+{% import _self as m %}
+
+{% if paginator|length > 1 %}
+
+{% endif %}
diff --git a/Tests/Pagination/PageTest.php b/Tests/Pagination/PageTest.php
new file mode 100644
index 000000000..2aa9b96f7
--- /dev/null
+++ b/Tests/Pagination/PageTest.php
@@ -0,0 +1,141 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Tests\Pagination;
+
+use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Chill\MainBundle\Pagination\Page;
+
+/**
+ * Test the Page class
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class PageTest extends KernelTestCase
+{
+ protected $paginator;
+
+ protected $prophet;
+
+ public function setUp() {
+ $this->prophet = new \Prophecy\Prophet;
+
+
+ }
+
+ /**
+ *
+ * @param int $maxResult
+ * @param int $itemPerPage
+ * @param string $route
+ * @param array $routeParameters
+ * @return Page
+ */
+ protected function generatePage(
+ $number = 1,
+ $itemPerPage = 10,
+ $route = 'route',
+ array $routeParameters = array()
+ ) {
+ $urlGenerator = $this->prophet->prophesize();
+ $urlGenerator->willImplement(UrlGeneratorInterface::class);
+
+ return new Page($number, $itemPerPage, $urlGenerator->reveal(), $route,
+ $routeParameters);
+ }
+
+ public function testPageNumber() {
+ $page = $this->generatePage(1);
+
+ $this->assertEquals(1, $page->getNumber());
+ }
+
+ /**
+ * return a set of element to testGetFirstItemNumber
+ *
+ * the set contains :
+ * - the page number ;
+ * - the number of item per page ;
+ * - the expected first item number
+ *
+ * @return array
+ */
+ public function generateGetFirstItemNumber() {
+ return array(
+ [1, 10, 0],
+ [2, 10, 10]
+ );
+ }
+
+ /**
+ *
+ * @param int $number
+ * @param int $itemPerPage
+ * @param int $expectedItemPerPage
+ * @dataProvider generateGetFirstItemNumber
+ */
+ public function testGetFirstItemNumber(
+ $number,
+ $itemPerPage,
+ $expectedItemPerPage
+ ) {
+ $page = $this->generatePage($number, $itemPerPage);
+
+ $this->assertEquals($expectedItemPerPage, $page->getFirstItemNumber());
+ }
+
+ /**
+ * return a set of element to testGetLastItemNumber
+ *
+ * the set contains :
+ * - the page number ;
+ * - the number of item per page ;
+ * - the expected last item number
+ *
+ * @return array
+ */
+ public function generateGetLastItemNumber() {
+ return array(
+ [1, 10, 9],
+ [2, 10, 19]
+ );
+ }
+
+ /**
+ *
+ * @param int $number
+ * @param int $itemPerPage
+ * @param int $expectedItemPerPage
+ * @dataProvider generateGetLastItemNumber
+ */
+ public function testGetLastItemNumber(
+ $number,
+ $itemPerPage,
+ $expectedItemPerPage
+ ) {
+ $page = $this->generatePage($number, $itemPerPage);
+
+ $this->assertEquals($expectedItemPerPage, $page->getLastItemNumber());
+ }
+
+
+}
diff --git a/Tests/Pagination/PaginatorTest.php b/Tests/Pagination/PaginatorTest.php
new file mode 100644
index 000000000..b1a234b94
--- /dev/null
+++ b/Tests/Pagination/PaginatorTest.php
@@ -0,0 +1,237 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+namespace Chill\MainBundle\Tests\Pagination;
+
+use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+use Chill\MainBundle\Pagination\Paginator;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+/**
+ * Test the paginator class
+ *
+ * @author Julien Fastré
+ * @author Champs Libres
+ */
+class PaginatorTest extends KernelTestCase
+{
+ protected $paginator;
+
+ protected $prophet;
+
+ public function setUp()
+ {
+ $this->prophet = new \Prophecy\Prophet;
+ }
+
+ /**
+ *
+ * @param int $maxResult
+ * @param int $itemPerPage
+ * @param string $route
+ * @param array $routeParameters
+ * @return Paginator
+ */
+ protected function generatePaginator(
+ $totalItems,
+ $itemPerPage,
+ $currentPageNumber = 1,
+ $route = '',
+ array $routeParameters = array()
+ ) {
+ $urlGenerator = $this->prophet->prophesize();
+ $urlGenerator->willImplement(UrlGeneratorInterface::class);
+
+ return new Paginator(
+ $totalItems,
+ $itemPerPage,
+ $currentPageNumber,
+ $route,
+ $routeParameters,
+ $urlGenerator->reveal(),
+ 'page',
+ 'item_per_page'
+ );
+ }
+
+ /**
+ * generate a set of pages with different maxItem, itemPerPage, and
+ * expected page number
+ *
+ * @return array
+ */
+ public function generatePageNumber()
+ {
+ return array(
+ [12, 10, 2],
+ [20, 10, 2],
+ [21, 10, 3],
+ [19, 10, 2],
+ [1, 10, 1],
+ [0, 10, 1],
+ [10, 10, 1]
+ );
+ }
+
+ /**
+ * Test that the countPages method (and his alias `count`) return
+ * valid results.
+ *
+ * @param int $totalItems
+ * @param int $itemPerPage
+ * @param int $expectedPageNumber
+ * @dataProvider generatePageNumber
+ */
+ public function testPageNumber($totalItems, $itemPerPage, $expectedPageNumber)
+ {
+ $paginator = $this->generatePaginator($totalItems, $itemPerPage);
+
+ $this->assertEquals($expectedPageNumber, $paginator->countPages());
+ $this->assertEquals($expectedPageNumber, count($paginator));
+ }
+
+ /**
+ * generate an array with a set of page with :
+ * - total items ;
+ * - item per page ;
+ * - current page number ;
+ * - expected hasNextPage result
+ *
+ * @return array
+ */
+ public function generateHasNextPage()
+ {
+ return array(
+ [10, 10, 1, false],
+ [20, 10, 1, true],
+ [12, 10, 1, true],
+ [12, 10, 2, false]
+ );
+ }
+
+ /**
+ *
+ * @param int $totalItems
+ * @param int $itemPerPage
+ * @param int $currentPage
+ * @param bool $expectedHasNextPage
+ * @dataProvider generateHasNextPage
+ */
+ public function testHasNextPage(
+ $totalItems,
+ $itemPerPage,
+ $currentPage,
+ $expectedHasNextPage
+ ) {
+ $paginator = $this->generatePaginator($totalItems, $itemPerPage, $currentPage);
+
+ $this->assertEquals($expectedHasNextPage, $paginator->hasNextPage());
+ }
+
+ /**
+ * generate an array with a set of page with :
+ * - total items ;
+ * - item per page ;
+ * - current page number ;
+ * - expected hasPreviousPage result
+ *
+ * @return array
+ */
+ public function generateHasPreviousPage()
+ {
+ return array(
+ [10, 10, 1, false],
+ [20, 10, 1, false],
+ [12, 10, 1, false],
+ [12, 10, 2, true],
+ );
+ }
+
+ /**
+ *
+ * @param int $totalItems
+ * @param int $itemPerPage
+ * @param int $currentPage
+ * @param bool $expectedHasPreviousPage
+ * @dataProvider generateHasPreviousPage
+ */
+ public function testHasPreviousPage(
+ $totalItems,
+ $itemPerPage,
+ $currentPage,
+ $expectedHasNextPage
+ ) {
+ $paginator = $this->generatePaginator($totalItems, $itemPerPage, $currentPage);
+
+ $this->assertEquals($expectedHasNextPage, $paginator->hasPreviousPage());
+ }
+
+ public function generateHasPage()
+ {
+ return array(
+ [10, 10, -1, false],
+ [12, 10, 1, true],
+ [12, 10, 2, true],
+ [12, 10, 3, false]
+ );
+ }
+
+ /**
+ * test the HasPage function
+ *
+ *
+ * @param int $totalItems
+ * @param int $itemPerpage
+ * @param int $pageNumber
+ * @param bool $expectedHasPage
+ * @dataProvider generateHasPage
+ */
+ public function testHasPage($totalItems, $itemPerpage, $pageNumber,
+ $expectedHasPage)
+ {
+ $paginator = $this->generatePaginator($totalItems, $itemPerpage);
+
+ $this->assertEquals($expectedHasPage, $paginator->hasPage($pageNumber));
+ }
+
+ public function testGetPage()
+ {
+ $paginator = $this->generatePaginator(105, 10);
+
+ $this->assertEquals(5, $paginator->getPage(5)->getNumber());
+ }
+
+ public function testPagesGenerator()
+ {
+ $paginator = $this->generatePaginator(105, 10);
+
+ $generator = $paginator->getPagesGenerator();
+
+ $i = 1;
+ foreach($generator as $page) {
+ $this->assertEquals($i, $page->getNumber(),
+ "assert that the current page number is $i");
+ $i++;
+ }
+
+ $this->assertEquals(11, $page->getNumber(),
+ "assert that the last page number is 11");
+ }
+}