porpaginas

A simple abstraction for paginated and non-paginated results

zenstruck/porpaginas

Build Status Scrutinizer Code Quality Code Coverage StyleCI Latest Stable Version License

NOTE: This library is a fork of beberlei/porpaginas.

This library solves a bunch of issues that comes up with APIs of Repository classes alot:

  • You need different methods for paginatable and non-paginatable finder methods.
  • You need to expose the underlying data-source and return query objects from your repository.
  • Serialization of paginators should be easily possible for REST APIs

Both Pagerfanta and KnpLabs Pager don't solve this issue and their APIs are really problematic in this regard. You need to return the query objects or adapters for paginators from your repositories to get it working and then use an API on the controller side to turn them into a paginated result set.

Porpaginas solves this by introducing a sane abstraction for paginated results. For rendering purposes you can integrate with either Pagerfanta or KnpLabs Pager, this library is not about reimplementating the view part of pagination.

Central part of this library is the interface Result:

namespace Zenstruck\Porpaginas;

interface Result extends \Countable, \IteratorAggregate, \JsonSerializable
{
    public function take(int $offset, int $limit): Page;

    /**
     * Return the number of all results in the paginatable.
     */
    public function count(): int;

    /**
     * Return an iterator over all results of the paginatable.
     */
    public function getIterator(): \Iterator;
}

This API offers you two ways to iterate over the paginatable result, either the full result or a paginated window of the result using take(). One drawback is that the query is always lazily executed inside the Result and not directly in the repository.

The Page interface returned from Result::take() looks like this:

namespace Zenstruck\Porpaginas;

interface Page extends \Countable, \IteratorAggregate, \JsonSerializable
{
    /**
     * Return the number of results on the currrent page.
     */
    public function count(): int;

    /**
     * Return the number of ALL results in the paginatable..
     */
    public function totalCount(): int;

    /**
     * Return an iterator over selected windows of results of the paginatable.
     */
    public function getIterator(): \Iterator;
}

Supported Backends

  • Array
  • Doctrine ORM
  • Doctrine DBAL

Example

Take the following example using Doctrine ORM:

use Zenstruck\Porpaginas\Result;

class UserRepository extends EntityRepository
{
    public function findAllUsers(): Result
    {
        $qb = $this->createQueryBuilder('u')->orderBy('u.username');

        return new ORMQueryResult($qb);
    }
}

class UserController
{
    /**
     * @var UserRepository
     */
    private $userRepository;

    public function listAction(Request $request)
    {
        $result = $this->userRepository->findAllUsers();
        // no filtering by page, iterate full result

        return array('users' => $result);
    }

    public function porpaginasListAction(Request $request)
    {
        $result = $this->userRepository->findAllUsers();

        $paginator = $result->take(($request->get('page', 1)-1) * 20, 20);

        return array('users' => $paginator);
    }
}

This library also comes with Pager helpers. Using the ResultPager, the above controller's porpaginasListAction() could be re-written as follows:

use Zenstruck\Porpaginas\Pager\ResultPager;

class UserController
{
    /**
     * @var UserRepository
     */
    private $userRepository;

    public function porpaginasListAction(Request $request)
    {
        $result = $this->userRepository->findAllUsers();

        $pager = new ResultPager($result, $request->get('page', 1);

        return array('users' => $pager);
    }
}

The MIT License

Copyright for portions of project "zenstruck\porpaginas" are held by
Benjamin Eberlei, 2015 as part of project "beberlei/porpaginas". All other
copyright for project "zenstruck\porpaginas" are held by Kevin Bond, 2015.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.