9
votes

I have been following tutorials, and all instructions show it's done the exact same way, but it doesn't seem to work in Symfony 4. Is there something I'm overlooking or is the bundle simply incompatible?

I ran: composer require knplabs/knp-paginator-bundle

It was loaded automatically into bundles.php, thanks to Flex.

Inserted the following into config/services.yaml:

knp_paginator:
    page_range:                 5          # default page range used in pagination control
    default_options:
        page_name:              page       # page query parameter name
        sort_field_name:        sort       # sort field query parameter name
        sort_direction_name:    direction  # sort direction query parameter name
        distinct:               true       # ensure distinct results, useful when ORM queries are using GROUP BY statements
    template:
        pagination: KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig     # sliding pagination controls template
        sortable: KnpPaginatorBundle:Pagination:sortable_link.html.twig                         # sort link template

Tried to use the following in the controller:

$paginator  = $this->get('knp_paginator');

and got the following error:

Service "knp_paginator" not found: even though it exists in the app's container, the container inside "App\Controller\PhotoController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "request_stack", "router", "security.authorization_checker", "security.token_storage", "serializer", "session" and "twig" services. Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "PhotoController::getSubscribedServices()".

4
Based on the error, it seems to me, I might've placed the knp_paginator yaml setup in the wrong place. But I can't find a place to put it without it crashing and saying it doesn't belong "there". When I place it indented from "services" it says "The configuration key "page_range" is unsupported for definition "knp_paginator"", which is.. lame.. - Darius
Try to create a new file into the config/packages directory with a name like 'knppaginator.yaml' and place your configuration in your new file instead of services.yaml - Frank B
Tried knp_paginator.yaml and knppaginator.yaml, no luck, same error. Funny though, I try messing with the configuration by purposefully mistyping it to knpS_paginator, it throws error saying "there is no extension able to load ...", so it knows knp_paginator is correct. - Darius
Tried it by my self. Made a file config/packages/knp_paginator.yaml and put configuration into it as example on github. Had to clear the cache and then it just worked. Make sure you use the extension yaml and not yml. - Frank B
@FrankB The issue was the "extends AbstractController", symfony recommended using abstract instead of regular controller. Malcolm showed how to do it while using abstractcontroller. Cache was being cleared, so it wasn't cache. - Darius

4 Answers

29
votes

You have to extend Controller instead of AbstractController class:

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MyController extends Controller
{

    public function myAction()
    {
        $paginator  = $this->get('knp_paginator');

or better leave AbstractController and inject knp_paginator service into your action:

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Knp\Component\Pager\PaginatorInterface;

class MyController extends AbstractController
{

    public function myAction(PaginatorInterface $paginator)
    {
        $paginator->paginate()...
    }
8
votes

In my case I use AbstractController and as malcolm says, it is beter to inject the service directrly in your action, even so, I call a method several times and I think that overwrite getSubscribedServices is clener for my porpuse.

public static function getSubscribedServices(): array
{
    $services = parent::getSubscribedServices();
    $services['fos_elastica.manager'] = RepositoryManagerInterface::class;
    $services['knp_paginator'] = PaginatorInterface::class;

    return $services;
}

private function listHandler(Search $search, Request $request, int $page): Response
{
    //...
    $repository = $this->container->get('fos_elastica.manager')->getRepository(Foo::class);
    //...

}
1
votes

As it says in the documentation. You must extend the base Controller class, or use dependency injection instead https://symfony.com/doc/current/service_container.html#service-parameters

0
votes

In my case i'm using symfony 4.3, I just injected the class to the methods as an argument and i'm done.

public function list(ProductManager $productManager)
{ 
   $products = $productManager->prepareProducts(); 
   return $products;
}