Skip to content

Commit

Permalink
Add new filter for empty fields
Browse files Browse the repository at this point in the history
  • Loading branch information
core23 committed Jul 3, 2020
1 parent 14e2a75 commit 0357430
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
21 changes: 21 additions & 0 deletions docs/reference/filter_field_definition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ For now, only `Doctrine ORM` filters are available:
* ``Sonata\DoctrineORMAdminBundle\Filter\DateTimeFilter``: depends on the ``Sonata\AdminBundle\Form\Type\Filter\DateTimeType`` Form Type, renders a datetime field,
* ``Sonata\DoctrineORMAdminBundle\Filter\DateTimeRangeFilter``: depends on the ``Sonata\AdminBundle\Form\Type\Filter\DateTimeRangeType`` Form Type, renders a 2 datetime fields,
* ``Sonata\DoctrineORMAdminBundle\Filter\ClassFilter``: depends on the ``Sonata\AdminBundle\Form\Type\Filter\DefaultType`` Form type, renders a choice list field.
* ``Sonata\DoctrineORMAdminBundle\Filter\EmptyFieldFilter``: depends on the ``Sonata\AdminBundle\Form\Type\Filter\DefaultType`` Form type, renders a choice list field.

Example
-------
Expand Down Expand Up @@ -162,6 +163,26 @@ ClassFilter
}
}

Empty
-----

``Sonata\DoctrineORMAdminBundle\Filter\EmptyFieldFilter`` supports filtering for empty (null) entity fields::

namespace Sonata\NewsBundle\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Filter\EmptyFieldFilter;

final class PostAdmin extends AbstractAdmin
{
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('deleted', EmptyFieldFilter::class, ['field_name' => 'deletedAt']);
}
}

Advanced usage
--------------

Expand Down
97 changes: 97 additions & 0 deletions src/Filter/EmptyFieldFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\DoctrineORMAdminBundle\Filter;

use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
use Sonata\AdminBundle\Form\Type\Filter\DefaultType;
use Sonata\Form\Type\BooleanType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;

final class EmptyFieldFilter extends Filter
{
/**
* @param string $alias
* @param string $field
* @param mixed[]|null $data
*/
public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data): void
{
if (null === $data || !\is_array($data) || !\array_key_exists('value', $data)) {
return;
}

if (BooleanType::TYPE_NO === (int) $data['value']) {
$this->applyWhere(
$queryBuilder,
$queryBuilder
->expr()
->isNull(sprintf('%s.%s', $alias, $field))
);
} elseif (BooleanType::TYPE_YES === (int) $data['value']) {
$this->applyWhere(
$queryBuilder,
$queryBuilder
->expr()
->isNotNull(sprintf('%s.%s', $alias, $field))
);
}
}

public function getDefaultOptions()
{
return [
'field_type' => BooleanType::class,
'operator_type' => HiddenType::class,
'operator_options' => [],
];
}

public function getRenderSettings()
{
return [DefaultType::class, [
'field_type' => $this->getFieldType(),
'field_options' => $this->getFieldOptions(),
'operator_type' => $this->getOption('operator_type'),
'operator_options' => $this->getOption('operator_options'),
'label' => $this->getLabel(),
]];
}

public function getParentAssociationMappings()
{
$mappings = $this->getOption('parent_association_mappings', []);

$fields = explode('.', $this->getFieldName(), -1);

foreach ($fields as $field) {
$mappings[] = ['fieldName' => $field];
}

return $mappings;
}

/**
* @param mixed|null $data
*
* @return string[]
*/
protected function association(ProxyQueryInterface $queryBuilder, $data): array
{
$alias = $queryBuilder->entityJoin($this->getParentAssociationMappings());
$part = strrchr('.'.$this->getFieldName(), '.');
$fieldName = substr(false === $part ? $this->getFieldType() : $part, 1);

return [$alias, $fieldName];
}
}
3 changes: 3 additions & 0 deletions src/Resources/config/doctrine_orm_filter_types.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@
<service id="sonata.admin.orm.filter.type.class" class="Sonata\DoctrineORMAdminBundle\Filter\ClassFilter">
<tag name="sonata.admin.filter.type" alias="doctrine_orm_class"/>
</service>
<service id="Sonata\DoctrineORMAdminBundle\Filter\EmptyFieldFilter">
<tag name="sonata.admin.filter.type" alias="doctrine_orm_empty"/>
</service>
</services>
</container>
33 changes: 33 additions & 0 deletions tests/Filter/EmptyFieldFilterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\DoctrineORMAdminBundle\Tests\Filter;

use PHPUnit\Framework\TestCase;
use Sonata\DoctrineORMAdminBundle\Filter\EmptyFieldFilter;
use Sonata\Form\Type\BooleanType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

final class EmptyFieldFilterTest extends TestCase
{
public function testRenderSettings(): void
{
$filter = new EmptyFieldFilter();
$filter->initialize('field_name', [
'field_options' => ['class' => 'FooBar'],
]);
$options = $filter->getRenderSettings()[1];

$this->assertSame(BooleanType::class, $options['field_type']);
}
}

0 comments on commit 0357430

Please sign in to comment.