diff --git a/src/Configuration/ShortFormTypeConfigPass.php b/src/Configuration/ShortFormTypeConfigPass.php index 11df2df0..91de0a4a 100644 --- a/src/Configuration/ShortFormTypeConfigPass.php +++ b/src/Configuration/ShortFormTypeConfigPass.php @@ -3,6 +3,7 @@ namespace AlterPHP\EasyAdminExtensionBundle\Configuration; use AlterPHP\EasyAdminExtensionBundle\Form\Type\EasyAdminEmbeddedListType; +use AlterPHP\EasyAdminExtensionBundle\Form\Type\ListFilterType; use AlterPHP\EasyAdminExtensionBundle\Form\Type\Security\AdminRolesType; use EasyCorp\Bundle\EasyAdminBundle\Configuration\ConfigPassInterface; use EasyCorp\Bundle\EasyAdminBundle\Form\Util\LegacyFormHelper; @@ -23,6 +24,7 @@ class ShortFormTypeConfigPass implements ConfigPassInterface private static $nativeShortFormTypes = array( 'embedded_list' => EasyAdminEmbeddedListType::class, 'admin_roles' => AdminRolesType::class, + 'operator' => ListFilterType::class ); public function __construct(array $customFormTypes = array()) diff --git a/src/EventListener/PostQueryBuilderSubscriber.php b/src/EventListener/PostQueryBuilderSubscriber.php index 665561b3..5cee65f0 100644 --- a/src/EventListener/PostQueryBuilderSubscriber.php +++ b/src/EventListener/PostQueryBuilderSubscriber.php @@ -2,9 +2,10 @@ namespace AlterPHP\EasyAdminExtensionBundle\EventListener; +use AlterPHP\EasyAdminExtensionBundle\Model\ListFilter; use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query\QueryException; +use Doctrine\ORM\QueryBuilder; use EasyCorp\Bundle\EasyAdminBundle\Event\EasyAdminEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\GenericEvent; @@ -14,6 +15,7 @@ */ class PostQueryBuilderSubscriber implements EventSubscriberInterface { + /** * @var \AlterPHP\EasyAdminExtensionBundle\Helper\ListFormFiltersHelper */ @@ -115,21 +117,28 @@ protected function applyRequestFilters(QueryBuilder $queryBuilder, array $filter protected function applyFormFilters(QueryBuilder $queryBuilder, array $filters = array()) { foreach ($filters as $field => $value) { + $value = $this->filterEasyadminAutocompleteValue($value); // Empty string and numeric keys is considered as "not applied filter" if (null === $value || '' === $value || \is_int($field)) { continue; } + // Add root entity alias if none provided $field = false === \strpos($field, '.') ? $queryBuilder->getRootAlias().'.'.$field : $field; + $property = $field; + if ($value instanceof ListFilter && $value->getProperty()) { + // if a property is specified in the ListFilter, it is on that property that we must filter + $property = $queryBuilder->getRootAlias().'.' .$value->getProperty(); + } // Checks if filter is directly appliable on queryBuilder - if (!$this->isFilterAppliable($queryBuilder, $field)) { + if (!$this->isFilterAppliable($queryBuilder, $property)) { continue; } // Sanitize parameter name $parameter = 'form_filter_'.\str_replace('.', '_', $field); - $this->filterQueryBuilder($queryBuilder, $field, $parameter, $value); + $this->filterQueryBuilder($queryBuilder, $property, $parameter, $value); } } @@ -170,6 +179,16 @@ protected function filterQueryBuilder(QueryBuilder $queryBuilder, string $field, $parameter = null; $filterDqlPart = $field.' IS NOT NULL'; break; + // Special case if value is a ListFilter + case $value instanceof ListFilter: + if ($value->getValue() === null || $value->getValue() === '') { + // Break if there is not value + break; + } + + $filterDqlPart = $field.' ' .$value->getOperator() .' :'.$parameter; + $value = $value->getValue(); + break; // Default is equality default: $filterDqlPart = $field.' = :'.$parameter; @@ -207,4 +226,5 @@ protected function isFilterAppliable(QueryBuilder $queryBuilder, string $field): return true; } + } diff --git a/src/Form/Type/ListFilterType.php b/src/Form/Type/ListFilterType.php new file mode 100644 index 00000000..24dcc4a3 --- /dev/null +++ b/src/Form/Type/ListFilterType.php @@ -0,0 +1,66 @@ + '=', + 'gt' => '>', + 'gte' => '>=', + 'lt' => '<', + 'lte' => '<=', + ]; + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $operator = $options['operator']; + if (!array_key_exists($operator, static::$operators)) { + throw new \InvalidArgumentException('operator should be one of ' . implode(', ', array_keys(static::$operators)) . ". $operator passed"); + } + + $property = $options['property']; + $type = $options['input_type']; + unset($options['operator'], $options['input_type'], $options['property']); + + $builder + ->add('value', $type, $options['input_type_options'] + [ + 'label' => false, + 'required' => false + ]) + ->add('operator', HiddenType::class, [ + 'data' => self::$operators[$operator] + ]); + if ($property !== null) { + $builder + ->add('property', HiddenType::class, [ + 'data' => $property + ]); + } + + } + + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'operator' => 'equals', + 'data_class' => ListFilter::class, + 'input_type' => TextType::class, + 'input_type_options' => [] + )); + $resolver->setDefined([ + 'property', + ]); + } +} diff --git a/src/Model/ListFilter.php b/src/Model/ListFilter.php new file mode 100644 index 00000000..032ba2a9 --- /dev/null +++ b/src/Model/ListFilter.php @@ -0,0 +1,51 @@ +operator; + } + + public function setOperator(string $operator) + { + $this->operator = $operator; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } + + public function getProperty() + { + return $this->property; + } + + public function setProperty($property) + { + $this->property = $property; + } + + +}