Skip to content

Instantly share code, notes, and snippets.

@merk
Last active October 10, 2015 14:17
Show Gist options
  • Save merk/3703011 to your computer and use it in GitHub Desktop.
Save merk/3703011 to your computer and use it in GitHub Desktop.
Use of a FormType to build a filter for a list of entities
<?php
namespace Ibms\JobBundle\Controller;
class JobController extends BaseJobController
{
/**
* Job list.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function listAction(Request $request)
{
$qb = $this->getJobManager()->queryAll('j');
$filter = $this->getJobFilter();
$filter->filter($qb);
$paginator = $this->container->get('knp_paginator');
$jobs = $paginator->paginate(
$qb,
$request->query->get('page', 1),
$request->query->get('pp', 15)
);
return $this->render('IbmsJobBundle:Job:list.html.twig', array(
'filter' => $filter->getView(),
'jobs' => $jobs,
));
}
}
<?php
namespace Ibms\JobBundle\Filter;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\Andx;
use Ibms\JobBundle\Entity\Status;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
class JobFilter
{
/**
* @var \Symfony\Component\Form\FormInterface
*/
private $form;
/**
* The constructor
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\Form\FormInterface $form
*/
public function __construct(Request $request, FormInterface $form)
{
$this->form = $form;
$this->form->setData(new JobFilterModel);
if ($request->query->count() > 0) {
$this->form->bind($request);
}
}
/**
* @return \Symfony\Component\Form\FormView
*/
public function getView()
{
return $this->form->createView();
}
/**
* @param \Doctrine\ORM\QueryBuilder $qb
*/
public function filter(QueryBuilder $qb)
{
/** @var $data JobFilterModel */
$data = $this->form->getData();
$conditions = new Andx;
if ($data->warrantySupplier) {
$qb->leftJoin('j.appliances', 'ja');
$conditions->add($qb->expr()->andX(
$qb->expr()->isNotNull('ja.warrantyClass'),
$qb->expr()->eq('IDENTITY(ja.warrantySupplier)', ':supplierId'),
'SIZE(j.appliances) > 0'
));
$qb->setParameter('supplierId', $data->warrantySupplier->getId());
}
if ($data->statuses->count()) {
$conditions->add($qb->expr()->in('IDENTITY(j.status)',
$data->statuses->map(function (Status $status) {
return $status->getId();
})->toArray()
));
} else {
$conditions->add($qb->expr()->neq('s.constant', ':cancelled'));
$qb->setParameter('cancelled', 'CANCELLED');
}
if ($data->scheduled) {
$day = $data->scheduled;
$conditions->add($qb->expr()->eq('j.scheduled', ':date'));
$qb->setParameter('date', $day->format('Y-m-d'));
}
if ($data->workshop) {
$conditions->add($qb->expr()->isNull('j.address'));
}
if ($data->unassigned) {
$conditions->add($qb->expr()->orX(
$qb->expr()->isNull('j.technician'),
$qb->expr()->eq('t.holding', ':holding'))
);
$qb->setParameter('holding', 1);
} elseif ($data->technician) {
$conditions->add($qb->expr()->eq('IDENTITY(j.technician)', ':technicianId'));
$qb->setParameter('technicianId', $data->technician->getId());
}
if ($conditions->count()) {
$qb->andWhere($conditions);
}
}
/**
* @return bool
*/
public function isSingleTechAndDay()
{
$data = $this->form->getData();
return $data->scheduled && $data->technician;
}
/**
* @return bool
*/
public function isWorkshopDay()
{
$data = $this->form->getData();
return $data->scheduled && !$data->technician && $data->workshop;
}
}
<?php
namespace Ibms\JobBundle\Filter;
use \Doctrine\Common\Collections\ArrayCollection;
class JobFilterModel
{
/**
* @var \Doctrine\Common\Collections\Collection<\Ibms\JobBundle\Entity\Status>
*/
public $statuses;
/**
* @var \DateTime|null
*/
public $scheduled;
/**
* @var Boolean
*/
public $workshop = false;
/**
* @var \Ibms\SupplierBundle\Entity\Supplier|null
*/
public $warrantySupplier;
/**
* @var \Ibms\UserBundle\Entity\Technician|null
*/
public $technician;
/**
* @var bool
*/
public $unassigned = false;
public function __construct()
{
$this->statuses = new ArrayCollection;
}
}
<?php
namespace Ibms\JobBundle\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class JobFilterType extends AbstractType
{
/**
* @param \Symfony\Component\Form\FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('statuses', 'entity', array(
'class' => 'Ibms\\JobBundle\\Entity\\Status',
'expanded' => true,
'multiple' => true,
'property' => 'name',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s')->addOrderBy('s.name');
},
'required' => false,
));
$builder->add('scheduled', 'date', array(
'required' => false,
'widget' => 'single_text',
));
$builder->add('workshop', 'checkbox', array(
'required' => false,
));
$builder->add('warrantySupplier', 'entity', array(
'class' => 'Ibms\\SupplierBundle\\Entity\\Supplier',
'empty_value' => 'None Selected',
'property' => 'name',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s')->addOrderBy('s.name');
},
'required' => false,
));
$builder->add('technician', 'entity', array(
'class' => 'Ibms\\UserBundle\\Entity\\Technician',
'empty_value' => 'None Selected',
'property' => 'user.fullName',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->addSelect('u')
->leftJoin('t.user', 'u')
->andWhere('u IS NOT NULL')
->orderBy('u.lastName')
->addOrderBy('u.firstName');
},
'required' => false,
));
$builder->add('unassigned', 'checkbox', array(
'required' => false,
));
}
/**
* @param \Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ibms\\JobBundle\\Filter\\JobFilterModel',
'csrf_protection' => false,
));
}
/**
* @return string
*/
public function getName()
{
return 'filter_job';
}
}
{# ... #}
{% set filterModel = filter.vars.value %}
{% block body %}
<form id="filter" class="well" action="" method="get" {{ form_enctype(filter) }}>
<div class="row">
{% if app.user.actuallyTechnician %}
<div class="span3">
{{ form_row(filter.technician) }}
</div>
<div class="span3">
{{ form_row(filter.scheduled, {
label: 'Date Scheduled'
}) }}
</div>
{% else %}
<div class="span3">
{{ form_row(filter.statuses, {
label: 'Job Statuses'
}) }}
</div>
<div class="span3">
{{ form_row(filter.scheduled, {
label: 'Date Scheduled'
}) }}
{{ form_row(filter.unassigned, {
label: 'Unassigned jobs only',
attr: {
'data-toggle-visible': '#technician-toggle',
'data-toggle-opposite': ''
}
}) }}
<div id="technician-toggle">
{{ form_row(filter.technician) }}
</div>
{{ form_row(filter.workshop, {
label: 'Show workshop jobs',
}) }}
</div>
<div class="span3">
{{ form_row(filter.warrantySupplier, {
help: 'Selecting a warranty supplier will list warranty jobs for that supplier',
label: 'Warranty Supplier'
}) }}
</div>
{% endif %}
</div>
<div class="row">
<button type="submit" class="pull-right btn btn-primary"><i class="icon-list-alt icon-white"></i> Update List</button>
{% if not app.user.technician %}<a href="{{ path('ibms_job_list') }}" class="pull-right btn"><i class="icon-share-alt"></i> Remove Filters</a>{% endif %}
</div>
</form>
{# ... #}
<service id="ibms_job.filter.job" class="Ibms\JobBundle\Filter\JobFilter" scope="request">
<argument type="service" id="request" />
<argument type="service" id="ibms_job.filter.job_form" />
</service>
<service id="ibms_job.filter.job_form" factory-method="createNamed" factory-service="form.factory" class="Symfony\Component\Form\Form">
<argument></argument>
<argument>filter_job</argument>
</service>
<service id="ibms_job.filter.job_form_type" class="Ibms\JobBundle\Filter\JobFilterType">
<tag name="form.type" alias="filter_job" />
</service>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment