0
votes

I'm trying to use this Symfony bundle: https://github.com/KnpLabs/KnpPaginatorBundle

In the docs, they use it a controller. So they have easy access to service container or the request object.

But as far as I understand, the Doctrine query should be in a repository, not a controller, right? And I already do have a function returning records. It's just that the pagination service doesn't expect "results" upon instantiating. It wants the query. So I can't return the "results" to the controller, but rather in middle of this function use a paginator.

On the other hand, stuff like playing with services or requests indeed belong to controllers.

So how this should be done? At first I thought about injecting the "knp_paginator" service and the request object into the repository. But I don't think this is the right way.

3

3 Answers

1
votes

I'd say that the Request object should not go further down the stack than from the Controller.

Nothing prevents you from injecting the paginator directly into your custom repository, so why not doing that?

your.repository.service.definition:
    class: Your\Repository\Class

    # for symfony 2.3
    factory_service: doctrine
    factory_method: getRepository

    # for symfony 2.8 and higher
    factory: ["@doctrine.orm.entity_manager", getRepository]

    arguments:
      - YourBundle:YourEntity
    calls:
        - [setPaginator, ["@knp_paginator"]]

In the repository, you then should have the paginator available for use with the QueryBuilder:

public function setPaginator($paginator)
{
    $this->paginator = $paginator;
}

...

$this->paginator->paginate($qb->getQuery(), $page, $limit);

In order to get your $page and $limit variables into the repository, you don't need the Request object. Simply pass them as a parameter to the repository call:

// In your controller
// You can use forms here if you want, but for brevity:
$criteria = $request->get('criteria');
$page = $request->get('page');
$limit = $request->get('limit');

$paginatedResults = $myCustomRepository->fetchPaginatedData($criteria, $page, $limit);

Passing the request object further down the Controller means that you have a leak in your abstractions. It's no concern of your application to know about the Request object. Actually, the request might well come from other sources such as the CLI command. You don't want to be creating a Request object from there because of a wrong level of abstraction.

1
votes

Assuming that you have a Custom Repository Class, you can have a method in that Repository, which returns a Query or a valid instance of Query Builder and then you call that method from the controller and pass it to the paginate() method.

1
votes

For example where $qb is returned by the custom repository (not return result but just the querybuilder of it)

$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
    $qb->getQuery(),
    $request->query->getInt($pageParameterName, 1),
    $perPage,
    array('pageParameterName' => $pageParameterName)
);