Skip to content

Commit

Permalink
List form filters are now submitted (#82)
Browse files Browse the repository at this point in the history
* List form filters are now submitted

* Better handling collection/array of list filter values

* debug travis testsuite

* Froce composer with dev requirements

* trying forcing csrf_protection on forms for Travis CI

* Try forcing framework.csrf_protection

* Fix Travis CI testsuite

* enable form
  • Loading branch information
alterphp committed Dec 6, 2018
1 parent c7afcbd commit 452fe30
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 29 deletions.
76 changes: 58 additions & 18 deletions src/EventListener/PostQueryBuilderSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace AlterPHP\EasyAdminExtensionBundle\EventListener;

use Doctrine\ORM\Query\QueryException;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\QueryException;
use EasyCorp\Bundle\EasyAdminBundle\Event\EasyAdminEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
Expand All @@ -13,6 +14,21 @@
*/
class PostQueryBuilderSubscriber implements EventSubscriberInterface
{
/**
* @var \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper
*/
protected $listFormFiltersHelper;

/**
* ListFormFiltersExtension constructor.
*
* @param \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper $listFormFiltersHelper
*/
public function __construct($listFormFiltersHelper)
{
$this->listFormFiltersHelper = $listFormFiltersHelper;
}

/**
* {@inheritdoc}
*/
Expand All @@ -33,9 +49,20 @@ public function onPostListQueryBuilder(GenericEvent $event)
{
$queryBuilder = $event->getArgument('query_builder');

// Request filters
if ($event->hasArgument('request')) {
$this->applyRequestFilters($queryBuilder, $event->getArgument('request')->get('filters', array()));
$this->applyFormFilters($queryBuilder, $event->getArgument('request')->get('form_filters', array()));
}

// List form filters
if ($event->hasArgument('entity')) {
$entityConfig = $event->getArgument('entity');
if (isset($entityConfig['list']['form_filters'])) {
$listFormFiltersForm = $this->listFormFiltersHelper->getListFormFilters($entityConfig['list']['form_filters']);
if ($listFormFiltersForm->isSubmitted() && $listFormFiltersForm->isValid()) {
$this->applyFormFilters($queryBuilder, $listFormFiltersForm->getData());
}
}
}
}

Expand Down Expand Up @@ -63,7 +90,7 @@ protected function applyRequestFilters(QueryBuilder $queryBuilder, array $filter
{
foreach ($filters as $field => $value) {
// Empty string and numeric keys is considered as "not applied filter"
if (\is_int($field) || '' === $value) {
if ('' === $value || \is_int($field)) {
continue;
}
// Add root entity alias if none provided
Expand All @@ -90,7 +117,7 @@ protected function applyFormFilters(QueryBuilder $queryBuilder, array $filters =
foreach ($filters as $field => $value) {
$value = $this->filterEasyadminAutocompleteValue($value);
// Empty string and numeric keys is considered as "not applied filter"
if (\is_int($field) || '' === $value) {
if (null === $value || '' === $value || \is_int($field)) {
continue;
}
// Add root entity alias if none provided
Expand Down Expand Up @@ -125,22 +152,35 @@ private function filterEasyadminAutocompleteValue($value)
*/
protected function filterQueryBuilder(QueryBuilder $queryBuilder, string $field, string $parameter, $value)
{
// For multiple value, use an IN clause, equality otherwise
if (\is_array($value)) {
$filterDqlPart = $field.' IN (:'.$parameter.')';
} elseif ('_NULL' === $value) {
$parameter = null;
$filterDqlPart = $field.' IS NULL';
} elseif ('_NOT_NULL' === $value) {
$parameter = null;
$filterDqlPart = $field.' IS NOT NULL';
} else {
$filterDqlPart = $field.' = :'.$parameter;
switch (true) {
// Multiple values leads to IN statement
case $value instanceof Collection:
case \is_array($value):
if (0 < count($value)) {
$filterDqlPart = $field.' IN (:'.$parameter.')';
}
break;
// Special value for NULL evaluation
case '_NULL' === $value:
$parameter = null;
$filterDqlPart = $field.' IS NULL';
break;
// Special value for NOT NULL evaluation
case '_NOT_NULL' === $value:
$parameter = null;
$filterDqlPart = $field.' IS NOT NULL';
break;
// Default is equality
default:
$filterDqlPart = $field.' = :'.$parameter;
break;
}

$queryBuilder->andWhere($filterDqlPart);
if (null !== $parameter) {
$queryBuilder->setParameter($parameter, $value);
if (isset($filterDqlPart)) {
$queryBuilder->andWhere($filterDqlPart);
if (null !== $parameter) {
$queryBuilder->setParameter($parameter, $value);
}
}
}

Expand Down
20 changes: 17 additions & 3 deletions src/Helper/ListFormFiltersHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace AlterPHP\EasyAdminExtensionBundle\Helper;

use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
Expand All @@ -28,20 +29,33 @@ class ListFormFiltersHelper
*/
private $listFiltersForm;

/**
* @var bool
*/
private $formCsrfEnabled;

/**
* @param FormFactory $formFactory
* @param RequestStack $requestStack
* @param bool $formCsrfEnabled
*/
public function __construct(FormFactory $formFactory, RequestStack $requestStack)
public function __construct(FormFactory $formFactory, RequestStack $requestStack, $formCsrfEnabled)
{
$this->formFactory = $formFactory;
$this->requestStack = $requestStack;
$this->formCsrfEnabled = $formCsrfEnabled;
}

public function getListFiltersForm(array $formFilters): FormInterface
public function getListFormFilters(array $formFilters): FormInterface
{
if (null === $this->listFiltersForm) {
$formBuilder = $this->formFactory->createNamedBuilder('form_filters');
$formOptions = array();
if ($this->formCsrfEnabled) {
$formOptions['csrf_protection'] = false;
}
$formBuilder = $this->formFactory->createNamedBuilder(
'form_filters', FormType::class, null, $formOptions
);

foreach ($formFilters as $name => $config) {
$formBuilder->add(
Expand Down
2 changes: 2 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="alterphp.easyadmin_extension.subscriber.post_query_builder" class="AlterPHP\EasyAdminExtensionBundle\EventListener\PostQueryBuilderSubscriber">
<argument type="service" id="alterphp.easyadmin_extension.helper.list_form_filters"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="alterphp.easyadmin_extension.config_pass.exclude_fields" class="AlterPHP\EasyAdminExtensionBundle\Configuration\ExcludeFieldsConfigPass">
Expand Down Expand Up @@ -42,6 +43,7 @@
<service id="alterphp.easyadmin_extension.helper.list_form_filters" class="AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper">
<argument type="service" id="form.factory"/>
<argument type="service" id="request_stack"/>
<argument>%form.type_extension.csrf.enabled%</argument>
</service>
<service id="alterphp.easyadmin_extension.twig.extension.list_form_filters" class="AlterPHP\EasyAdminExtensionBundle\Twig\ListFormFiltersExtension">
<argument type="service" id="alterphp.easyadmin_extension.helper.list_form_filters"/>
Expand Down
10 changes: 5 additions & 5 deletions src/Twig/ListFormFiltersExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ class ListFormFiltersExtension extends AbstractExtension
/**
* @var \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper
*/
protected $listFiltersHelper;
protected $listFormFiltersHelper;

/**
* ListFormFiltersExtension constructor.
*
* @param \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper $listFiltersHelper
* @param \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper $listFormFiltersHelper
*/
public function __construct($listFiltersHelper)
public function __construct($listFormFiltersHelper)
{
$this->listFiltersHelper = $listFiltersHelper;
$this->listFormFiltersHelper = $listFormFiltersHelper;
}

public function getFunctions()
Expand All @@ -31,6 +31,6 @@ public function getFunctions()

public function getListFormFilters(array $filters)
{
return $this->listFiltersHelper->getListFiltersForm($filters)->createView();
return $this->listFormFiltersHelper->getListFormFilters($filters)->createView();
}
}
4 changes: 2 additions & 2 deletions tests/Controller/ListFormFiltersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public function testFormSingleFilterIsApplied()
$this->assertSame(10, $crawler->filter('#main tr[data-id]')->count());
}

public function testFormSingleEasyadminAutocomplteFilterIsApplied()
public function testFormSingleEasyadminAutocompleteFilterIsApplied()
{
$crawler = $this->requestListView('Product', array(), array('category' => array('autocomplete' => 1)));
$crawler = $this->requestListView('Product', array(), array('category' => array('autocomplete' => array(1))));

$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$this->assertSame(10, $crawler->filter('#main tr[data-id]')->count());
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/App/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ framework:
default_locale: '%locale%'
test: ~
router: { resource: '%kernel.root_dir%/config/routing_base.yml' }
form: true
form: true
validation: { enable_annotations: true }
templating: { engines: ['twig'] }
profiler:
Expand Down

0 comments on commit 452fe30

Please sign in to comment.