Question

I have a list of items to display on a page, with a search form above it to filter these items, like in any usual backend. The problem is that I don't know how to add the search criteria to an existing query with joins... Here's what I have:

I use a specific method on the repository associated to the entity to add joins on the query (in order to avoid many queries). The controller looks like this:

class ModelController extends Controller
{
    public function indexAction(Request $request)
    {
        // ...
        $em = $this->getDoctrine()->getManager();
        $query = $em->getRepository('AcmeDemoBundle:Item')->getList();
    }
}

The getList method on the repository looks like this:

use Doctrine\ORM\EntityRepository;

// ...

class ItemRepository extends EntityRepository
{
    public function getList()
    {
        $queryBuilder = $this
            ->createQueryBuilder('i')
            ->innerJoin('i.brand', 'b');

        return $queryBuilder->getQuery();
    }
}

I created a ItemSearchType form object with several fields to search for items.

How can I easily add the search criteria from the data provided in the search form to display the filtered items?

This is what's in my controller concerning the search form:

class ModelController extends Controller
{
    public function indexAction(Request $request)
    {

        // ...
        if ($request->getMethod() === 'POST') {
           $searchForm->bindRequest($request);

           if ($searchForm->isValid()) {
               $searchCriteria = $searchForm->getData();

              // Do something with this data! ...but I don't know how
           }
     }
}

Thanks!

Was it helpful?

Solution

Here's what i would try:

public function getListBy($criteria)
{
    $qb = $this->createQueryBuilder('i');

    $qb->innerJoin('i.brand', 'b');

    foreach ($criteria as $field => $value) {
        if (!$this->getClassMetadata()->hasField($field)) {
            // Make sure we only use existing fields (avoid any injection)
            continue;
        }

        $qb ->andWhere($qb->expr()->eq('i.'.$field, ':i_'.$field))
            ->setParameter('i_'.$field, $value);
    }

    return $qb->getQuery()->getResult();
}

OTHER TIPS

Here I posted an answer for this, I use LexikFormFilterBundle filterTypes and QueryBuilder, plus a TypeGuesser I made that abstracts the filterForm creation process.

you can install both services as separate Bundles with Composer. The resulting code is cleaner

From the README, in case you don't want to navigate to github :P

/**
 * Creates a Filter form to search for Entities.
 *
 * @param AbstractType|string $formType The `generate:doctrine:form` generated Type or its FQCN.
 *
 * @return \Symfony\Component\Form\Form The filter Form
 */
private function createFilterForm($formType)
{
    $adapter = $this->get('dd_form.form_adapter');
    $form = $adapter->adaptForm(
        $formType,
        $this->generateUrl('document_search'),
        array('fieldToRemove1', 'fieldToRemove2')
    );
    return $form;
}

It's broken for SF >= 2.8 Need a fix here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top