diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3514ed3..147a510 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: fail-fast: false matrix: include: - - { php: 8.2, symfony: "6.4.*", composer-flags: '--prefer-dist' } # Lowest deps - - { php: 8.3, symfony: "6.4.*", composer-flags: '--prefer-dist' } # LTS with last stable PHP - - { php: 8.3, symfony: "7.1.*", composer-flags: '--prefer-dist' } # Stable Symfony branches - - { php: 8.4, symfony: "7.2.*", composer-flags: '--prefer-dist' } # Stable Symfony branches + - { php: 8.1, symfony: "5.4.*", composer-flags: '--prefer-dist' } + - { php: 8.1, symfony: "6.4.*", composer-flags: '--prefer-dist' } + - { php: 8.2, symfony: "7.4.*", composer-flags: '--prefer-dist' } + - { php: 8.4, symfony: "8.0.*", composer-flags: '--prefer-dist' } steps: - name: "Checkout" diff --git a/DependencyInjection/SpiriitFormFilterExtension.php b/DependencyInjection/SpiriitFormFilterExtension.php index d006802..3d2ceb8 100644 --- a/DependencyInjection/SpiriitFormFilterExtension.php +++ b/DependencyInjection/SpiriitFormFilterExtension.php @@ -15,8 +15,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\Extension; -use Symfony\Component\DependencyInjection\Loader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; /** * This is the class that loads and manages your bundle configuration @@ -35,13 +34,13 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); - $loader->load('services.xml'); - $loader->load('form.xml'); + $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.yaml'); + $loader->load('form.yaml'); foreach ($config['listeners'] as $name => $enable) { if ($enable) { - $loader->load(sprintf('%s.xml', $name)); + $loader->load(sprintf('%s.yaml', $name)); } } diff --git a/Filter/Condition/ConditionBuilder.php b/Filter/Condition/ConditionBuilder.php index de266b2..bb41397 100644 --- a/Filter/Condition/ConditionBuilder.php +++ b/Filter/Condition/ConditionBuilder.php @@ -29,11 +29,11 @@ public function root($operator): ConditionNode { $operator = strtolower($operator); - if (!in_array($operator, [ConditionNodeInterface::EXPR_AND, ConditionNodeInterface::EXPR_OR])) { + if (!in_array($operator, [ConditionNodeInterface::EXPR_AND, ConditionNodeInterface::EXPR_OR], true)) { throw new RuntimeException(sprintf('Invalid operator "%s", allowed values: and, or', $operator)); } - $this->root = new ConditionNode($operator, null); + $this->root = new ConditionNode($operator); return $this->root; } diff --git a/Resources/config/doctrine_orm.xml b/Resources/config/doctrine_orm.xml deleted file mode 100644 index b9b8576..0000000 --- a/Resources/config/doctrine_orm.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Spiriit\Bundle\FormFilterBundle\Event\Subscriber\DoctrineORMSubscriber - Spiriit\Bundle\FormFilterBundle\Event\Listener\DoctrineApplyFilterListener - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\EntityFilterType - - - - - - - - - - %spiriit_form_filter.where_method% - - - - - - - - - - diff --git a/Resources/config/doctrine_orm.yaml b/Resources/config/doctrine_orm.yaml new file mode 100644 index 0000000..9804afc --- /dev/null +++ b/Resources/config/doctrine_orm.yaml @@ -0,0 +1,26 @@ +parameters: + spiriit_form_filter.get_filter.doctrine_orm.class: Spiriit\Bundle\FormFilterBundle\Event\Subscriber\DoctrineORMSubscriber + spiriit_form_filter.apply_filter.doctrine_orm.class: Spiriit\Bundle\FormFilterBundle\Event\Listener\DoctrineApplyFilterListener + spiriit_form_filter.type.filter_entity.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\EntityFilterType + +services: + # Listeners + spiriit_form_filter.get_filter.doctrine_orm: + class: '%spiriit_form_filter.get_filter.doctrine_orm.class%' + tags: + - { name: kernel.event_subscriber } + + spiriit_form_filter.apply_filter.doctrine_orm: + class: '%spiriit_form_filter.apply_filter.doctrine_orm.class%' + arguments: + - '%spiriit_form_filter.where_method%' + tags: + - { name: kernel.event_listener, event: spiriit_filter.apply_filters.orm, method: onApplyFilterCondition } + + # Specific ORM types + spiriit_form_filter.type.filter_entity: + class: '%spiriit_form_filter.type.filter_entity.class%' + arguments: + - '@doctrine' + tags: + - { name: form.type } diff --git a/Resources/config/form.xml b/Resources/config/form.xml deleted file mode 100644 index 6a532bd..0000000 --- a/Resources/config/form.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberRangeFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\CheckboxFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\BooleanFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateRangeFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeRangeFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\CollectionAdapterFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\SharedableFilterType - Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\EnumFilterType - - - Spiriit\Bundle\FormFilterBundle\Filter\Form\FilterTypeExtension - - - - - - %spiriit_form_filter.text.condition_pattern% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/config/form.yaml b/Resources/config/form.yaml new file mode 100644 index 0000000..95cd2ac --- /dev/null +++ b/Resources/config/form.yaml @@ -0,0 +1,93 @@ +parameters: + # Filter Types + spiriit_form_filter.type.filter_text.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType + spiriit_form_filter.type.filter_number.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType + spiriit_form_filter.type.filter_number_range.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberRangeFilterType + spiriit_form_filter.type.filter_checkbox.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\CheckboxFilterType + spiriit_form_filter.type.filter_boolean.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\BooleanFilterType + spiriit_form_filter.type.filter_choice.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType + spiriit_form_filter.type.filter_date.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateFilterType + spiriit_form_filter.type.filter_date_range.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateRangeFilterType + spiriit_form_filter.type.filter_datetime.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeFilterType + spiriit_form_filter.type.filter_datetime_range.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeRangeFilterType + spiriit_form_filter.type.filter_collection_adapter.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\CollectionAdapterFilterType + spiriit_form_filter.type.filter_sharedable.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\SharedableFilterType + spiriit_form_filter.type.filter_enum.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\EnumFilterType + + # Type extension + spiriit_form_filter.type_extension.filter_extension.class: Spiriit\Bundle\FormFilterBundle\Filter\Form\FilterTypeExtension + +services: + # Filter Types + spiriit_form_filter.type.filter_text: + class: '%spiriit_form_filter.type.filter_text.class%' + arguments: + - '%spiriit_form_filter.text.condition_pattern%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_number: + class: '%spiriit_form_filter.type.filter_number.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_number_range: + class: '%spiriit_form_filter.type.filter_number_range.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_checkbox: + class: '%spiriit_form_filter.type.filter_checkbox.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_boolean: + class: '%spiriit_form_filter.type.filter_boolean.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_choice: + class: '%spiriit_form_filter.type.filter_choice.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_date: + class: '%spiriit_form_filter.type.filter_date.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_date_range: + class: '%spiriit_form_filter.type.filter_date_range.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_datetime: + class: '%spiriit_form_filter.type.filter_datetime.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_datetime_range: + class: '%spiriit_form_filter.type.filter_datetime_range.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_collection_adapter: + class: '%spiriit_form_filter.type.filter_collection_adapter.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_sharedable: + class: '%spiriit_form_filter.type.filter_sharedable.class%' + tags: + - { name: form.type } + + spiriit_form_filter.type.filter_enum: + class: '%spiriit_form_filter.type.filter_enum.class%' + tags: + - { name: form.type } + + # Type extension + spiriit_form_filter.type_extension.filter_extension: + class: '%spiriit_form_filter.type_extension.filter_extension.class%' + tags: + - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType } diff --git a/Resources/config/services.xml b/Resources/config/services.xml deleted file mode 100644 index f283721..0000000 --- a/Resources/config/services.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderUpdater - Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\FormDataExtractor - Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\DefaultExtractionMethod - Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\TextExtractionMethod - Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\ValueKeysExtractionMethod - Spiriit\Bundle\FormFilterBundle\Event\Listener\PrepareListener - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/config/services.yaml b/Resources/config/services.yaml new file mode 100644 index 0000000..40d7444 --- /dev/null +++ b/Resources/config/services.yaml @@ -0,0 +1,50 @@ +parameters: + spiriit_form_filter.query_builder_updater.class: Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderUpdater + spiriit_form_filter.form_data_extractor.class: Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\FormDataExtractor + spiriit_form_filter.data_extraction_method.default.class: Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\DefaultExtractionMethod + spiriit_form_filter.data_extraction_method.text.class: Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\TextExtractionMethod + spiriit_form_filter.data_extraction_method.key_values.class: Spiriit\Bundle\FormFilterBundle\Filter\DataExtractor\Method\ValueKeysExtractionMethod + spiriit_form_filter.filter_prepare.class: Spiriit\Bundle\FormFilterBundle\Event\Listener\PrepareListener + +services: + # Query builder updater and aliases for autowiring + Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderUpdater: + alias: spiriit_form_filter.query_builder_updater + public: false + + Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderUpdaterInterface: + alias: spiriit_form_filter.query_builder_updater + public: false + + spiriit_form_filter.query_builder_updater: + class: '%spiriit_form_filter.query_builder_updater.class%' + public: true + arguments: + - '@spiriit_form_filter.form_data_extractor' + - '@event_dispatcher' + + # Form data extraction + spiriit_form_filter.form_data_extractor: + class: '%spiriit_form_filter.form_data_extractor.class%' + + spiriit_form_filter.data_extraction_method.default: + class: '%spiriit_form_filter.data_extraction_method.default.class%' + tags: + - { name: spiriit_form_filter.data_extraction_method } + + spiriit_form_filter.data_extraction_method.text: + class: '%spiriit_form_filter.data_extraction_method.text.class%' + tags: + - { name: spiriit_form_filter.data_extraction_method } + + spiriit_form_filter.data_extraction_method.key_values: + class: '%spiriit_form_filter.data_extraction_method.key_values.class%' + tags: + - { name: spiriit_form_filter.data_extraction_method } + + # Prepare listener + spiriit_form_filter.filter_prepare: + class: '%spiriit_form_filter.filter_prepare.class%' + public: true + tags: + - { name: kernel.event_listener, event: spiriit_filter.prepare, method: onFilterBuilderPrepare } diff --git a/Tests/DependencyInjection/AutowiringTest.php b/Tests/DependencyInjection/AutowiringTest.php index a22f6f1..d018be7 100644 --- a/Tests/DependencyInjection/AutowiringTest.php +++ b/Tests/DependencyInjection/AutowiringTest.php @@ -18,10 +18,8 @@ use Spiriit\Bundle\FormFilterBundle\Tests\Stubs\Autowired; use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; -use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; -use Symfony\Component\HttpKernel\Kernel; class AutowiringTest extends TestCase { @@ -62,9 +60,9 @@ private static function createContainerBuilder(array $configs = []): ContainerBu 'kernel.cache_dir' => __DIR__, 'kernel.debug' => false, 'kernel.environment' => 'test', - 'kernel.name' => 'kernel', - 'kernel.root_dir' => __DIR__, 'kernel.project_dir' => __DIR__, + 'kernel.share_dir' => __DIR__, + 'kernel.runtime_mode.web' => false, 'kernel.container_class' => 'AutowiringTestContainer', 'kernel.charset' => 'utf8', 'kernel.runtime_environment' => 'test', diff --git a/Tests/Fixtures/Filter/FormType.php b/Tests/Fixtures/Filter/FormType.php index f44275e..93e773e 100644 --- a/Tests/Fixtures/Filter/FormType.php +++ b/Tests/Fixtures/Filter/FormType.php @@ -28,7 +28,7 @@ class FormType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('name', TextType::class); - $builder->add('position', IntegerType::class, ['apply_filter' => function (QueryInterface $filterQuery, $field, $values) { + $builder->add('position', IntegerType::class, ['apply_filter' => function (QueryInterface $filterQuery, $field, array $values) { if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { $expr = $filterQuery->getExpr()->field($field)->equals($values['value']); diff --git a/Tests/Fixtures/Filter/InheritDataFilterType.php b/Tests/Fixtures/Filter/InheritDataFilterType.php index 8d775d5..176ea01 100644 --- a/Tests/Fixtures/Filter/InheritDataFilterType.php +++ b/Tests/Fixtures/Filter/InheritDataFilterType.php @@ -30,7 +30,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder ->add('item', ItemFilterType::class, [ 'add_shared' => function (FilterBuilderExecuterInterface $qbe): void { - $closure = function (QueryBuilder $filterBuilder, string $alias, $joinAlias, Expr $expr): void { + $closure = function (QueryBuilder $filterBuilder, string $alias, string $joinAlias, Expr $expr): void { $filterBuilder->leftJoin($alias . '.item', $joinAlias); }; diff --git a/Tests/Fixtures/Filter/ItemCallbackFilterType.php b/Tests/Fixtures/Filter/ItemCallbackFilterType.php index 63e5e57..b9c5df1 100644 --- a/Tests/Fixtures/Filter/ItemCallbackFilterType.php +++ b/Tests/Fixtures/Filter/ItemCallbackFilterType.php @@ -28,7 +28,7 @@ class ItemCallbackFilterType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('name', TextFilterType::class, ['apply_filter' => [$this, 'fieldNameCallback']]); - $builder->add('position', NumberFilterType::class, ['apply_filter' => function (QueryInterface $filterQuery, $field, $values) { + $builder->add('position', NumberFilterType::class, ['apply_filter' => function (QueryInterface $filterQuery, $field, array $values) { if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { $expr = $filterQuery->getExpr()->field($field)->notEqual($values['value']); @@ -48,7 +48,7 @@ public function getBlockPrefix(): string return 'item_filter'; } - public function fieldNameCallback(QueryInterface $filterQuery, $field, $values) + public function fieldNameCallback(QueryInterface $filterQuery, $field, array $values) { if (!empty($values['value'])) { if ($filterQuery->getExpr() instanceof Expr) { diff --git a/Tests/Fixtures/Filter/ItemEmbeddedOptionsFilterType.php b/Tests/Fixtures/Filter/ItemEmbeddedOptionsFilterType.php index 88dfc17..5787947 100644 --- a/Tests/Fixtures/Filter/ItemEmbeddedOptionsFilterType.php +++ b/Tests/Fixtures/Filter/ItemEmbeddedOptionsFilterType.php @@ -30,8 +30,8 @@ class ItemEmbeddedOptionsFilterType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { - $addShared = function (FilterBuilderExecuterInterface $qbe): void { - $joinClosure = function (QueryBuilder $filterBuilder, string $alias, $joinAlias, ORMExpr $expr): void { + $addShared = static function (FilterBuilderExecuterInterface $qbe): void { + $joinClosure = function (QueryBuilder $filterBuilder, string $alias, string $joinAlias, ORMExpr $expr): void { $filterBuilder->leftJoin($alias . '.options', $joinAlias); }; $qbe->addOnce($qbe->getAlias() . '.options', 'opt', $joinClosure); diff --git a/composer.json b/composer.json index be7e78c..83d6762 100644 --- a/composer.json +++ b/composer.json @@ -10,15 +10,17 @@ "php": "^8.1", "doctrine/orm": "^3.0", "symfony/deprecation-contracts": "^3.5", - "symfony/form": "^5.4|^6.4|^7.0", - "symfony/framework-bundle": "^5.4|^6.4|^7.0" + "symfony/form": "^5.4|^6.4|^7.4|^8.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.4|^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "doctrine/doctrine-bundle": "^1.8 || ^2.0", + "doctrine/doctrine-bundle": "^1.8 || ^2.0 || ^3.0", "rector/rector": "^2.0", - "symfony/phpunit-bridge": "^5.4|^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.4|^7.0", + "symfony/phpunit-bridge": "^5.4|^6.4|^7.4|^8.0", + "symfony/var-dumper": "^5.4|^6.4|^7.4|^8.0", + "symfony/var-exporter": "^5.4|^6.4|^7.4", + "symfony/yaml": "^5.4|^6.4|^7.4|^8.0", "symplify/easy-coding-standard": "^12.5" }, "autoload": {