Search code examples
symfonyknppaginator

Symfony KnpPaginator query with Custom filters from form fields?


I'm creating a form that modifies the query of KnpPaginatorBundle in order to show filtered paginated results.

To do that. When the form is valid I build the querystring (concatenating) with the required fields to filter. I set $filteredDql variable with my custom query. The problem is that it's value only remains for the first page. When I change the page it turns to NULL. And pagination resets...

I think, the problem could be that I'm setting the $filteredDql variable in a block context (when the form is valid only).

How I can set $filteredDql variable for the whole operation or application wide ? maybe using parameters ? I tried using the container from the controller without success using:

$this->container->setParameter('key', value);
$this->container->getParameter('key');
$this->container->HasParameter('key');

But this way I'm getting 500 Internal Server Error

Here's the code:

public function indexAction(Request $request, $page)
{
    $filters = new Filters();

    $form = $this->createForm(new FiltersType(), $filters);

    $dql = "SELECT a FROM ViciousAmateurBundle:Post a WHERE a.is_active = true";

    if ($request->isMethod('POST')) {
        $form->bind($request);

        if ($form->isValid()) {
            $country = $filters->getCountry();
            $city = $filters->getCity();
            $gender = $filters->getGender();
            $sexualOrientation = $filters->getSexualOrientation();

            if (isset($country)) {
                $dql .= " AND a.country = '" . $filters->getCountry() . "'";
            }
            if (isset($city)) {
                $dql .= " AND a.city = '" . $filters->getCity() . "'";
            }
            if (isset($gender)) {
                $dql .= " AND a.gender = '" . $filters->getGender() . "'";
            }
            if (isset($sexualOrientation)) {
                $dql .= " AND a.sexual_orientation = '" . $filters->getSexualOrientation() . "'";
            }
            $filteredDql = $dql;
        }
    }

    $em = $this->get('doctrine.orm.entity_manager');

    if (isset($filteredDql)) {
        $query = $em->createQuery($filteredDql);
    } else {
        $query = $em->createQuery($dql);
    }

    $paginator = $this->get('knp_paginator');
    $pagination = $paginator->paginate(
        $query,
        $this->get('request')->query->get('page', $page),
        5
    );

    return $this->render('ViciousAmateurBundle:Default:index.html.twig', array(
        'form' => $form->createView(),
        'pagination' => $pagination
        )
    );
}

Solution

  • Finally solved it using a session variable to store the current filters. Sessions are application wide or stateless. I'm quite happy with this approach :D

    Although, It's a shame that KnpPaginatorBundle can't remember custom query "filters" (WHERE, GROUP BY, ...) through pagination by default when data comes from form validation :S And just support it by using the sortable functions to make links to sort asc or desc its a shame...

    Here's the code:

    /**
     * @Route("/{page}", defaults={"page" = 1}, name="homepage")
     * @Route("/")
     * @Template()
     */
    public function indexAction(Request $request, $page)
    {
        $filters = new Filters();
    
        $form = $this->createForm(new FiltersType(), $filters);
    
        $session = $this->getRequest()->getSession();
    
        if ($session->get('dql') == null) {
            $session->set('dql', "SELECT a FROM ViciousAmateurBundle:Post a WHERE a.is_active = true");
        }
    
        if ($request->isMethod('POST')) {
            $form->bind($request);
    
            if ($form->isValid()) {
                $dql = "SELECT a FROM ViciousAmateurBundle:Post a WHERE a.is_active = true";
                $country = $filters->getCountry();
                $city = $filters->getCity();
                $gender = $filters->getGender();
                $sexualOrientation = $filters->getSexualOrientation();
    
                if (isset($country)) {
                    $dql .= " AND a.country = '" . $filters->getCountry() . "'";
                }
                if (isset($city)) {
                    $dql .= " AND a.city = '" . $filters->getCity() . "'";
                }
                if (isset($gender)) {
                    $dql .= " AND a.gender = '" . $filters->getGender() . "'";
                }
                if (isset($sexualOrientation)) {
                    $dql .= " AND a.sexual_orientation = '" . $filters->getSexualOrientation() . "'";
                }
    
                $session->set('dql', $dql);
            }
        }
    
        $em = $this->get('doctrine.orm.entity_manager');
    
        $query = $em->createQuery($session->get('dql'));
    
        $paginator = $this->get('knp_paginator');
        $pagination = $paginator->paginate(
            $query,
            $this->get('request')->query->get('page', $page),
            5
        );
    
        return $this->render('ViciousAmateurBundle:Default:index.html.twig', array(
            'form' => $form->createView(),
            'pagination' => $pagination
            )
        );
    }