diff --git a/Filter/FilterBuilderUpdater.php b/Filter/FilterBuilderUpdater.php index 723ebc4..d144dec 100644 --- a/Filter/FilterBuilderUpdater.php +++ b/Filter/FilterBuilderUpdater.php @@ -161,7 +161,11 @@ protected function addFilters(FormInterface $form, QueryInterface $filterQuery, } elseif ($formType instanceof EmbeddedFilterTypeInterface) { $this->addFilters($child, $filterQuery, $child->getConfig()->getAttribute('filter_field_name') ?? ($alias . '.' . $child->getName())); - // default case + // inherit_data set to true + } elseif ($child->getConfig()->getInheritData()) { + $this->addFilters($child, $filterQuery, $alias); + + // default case } else { $condition = $this->getFilterCondition($child, $formType, $filterQuery, $alias); @@ -194,7 +198,11 @@ protected function getFilterCondition(FormInterface $form, AbstractType $formTyp $parentForm = $form; do { $parentForm = $parentForm->getParent(); - if (!is_numeric($parentForm->getName()) && $parentForm->getConfig()->getMapped()) { // skip collection numeric index and not mapped fields + if ( + !is_numeric($parentForm->getName()) + && $parentForm->getConfig()->getMapped() + && !$parentForm->getConfig()->getInheritData() + ) { // skip collection numeric index and not mapped fields and inherited data $completeName = $parentForm->getName() . '.' . $completeName; } } while (!$parentForm->isRoot()); @@ -295,6 +303,11 @@ protected function buildDefaultConditionNode(Form $form, ConditionNodeInterface $root->andX(), $name ); + } elseif ($child->getConfig()->getInheritData()) { + $this->buildDefaultConditionNode( + $child, + $root + ); } else { $root->field($name); } diff --git a/README.md b/README.md index 6afb4aa..d1990c0 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,8 @@ Please consider [opening a question on StackOverflow](http://stackoverflow.com/q Github Issues are dedicated to bug reports and feature requests. -Symfony 2.8 and 3.4 -------------------- +For compatibility with Symfony 2.8 and 3.4 +------------------------------------------ Please use last tag v5.* diff --git a/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php b/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php index 564d1be..9c80324 100644 --- a/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php +++ b/Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php @@ -13,6 +13,8 @@ use Spiriit\Bundle\FormFilterBundle\Filter\Condition\ConditionBuilderInterface; use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item; +use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Options; +use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter\InheritDataFilterType; use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter\ItemEmbeddedOptionsFilterType; /** @@ -177,10 +179,34 @@ public function testWithDataClass() $this->assertEquals(['p_opt_rank' => 6], $this->getQueryBuilderParameters($doctrineQueryBuilder)); } - protected function createDoctrineQueryBuilder() + public function testWithInheritDataFormOption() { + // doctrine query builder without any joins + a data_class + $form = $this->formFactory->create(InheritDataFilterType::class, null, ['data_class' => Options::class]); + $filterQueryBuilder = $this->initQueryBuilderUpdater(); + + $doctrineQueryBuilder = $this->createDoctrineQueryBuilder(Options::class, 'o'); + + $form->submit(['option' => ['label' => 'dude', 'rank' => 1], 'item' => ['name' => 'blabla', 'position' => 2, 'enabled' => 'y']]); + + $expectedDql = 'SELECT o FROM Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Options o LEFT JOIN o.item item'; + $expectedDql .= ' WHERE o.label LIKE \'dude\' AND o.rank = :p_o_rank AND (item.name LIKE \'blabla\' AND item.position > :p_item_position AND item.enabled = :p_item_enabled)'; + $filterQueryBuilder->addFilterConditions($form, $doctrineQueryBuilder); + + $this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql()); + $this->assertEquals([ + 'p_o_rank' => 1.0, + 'p_item_position' => 2.0, + 'p_item_enabled' => true, + ], $this->getQueryBuilderParameters($doctrineQueryBuilder)); + } + + protected function createDoctrineQueryBuilder( + string $entityClassName = Item::class, + string $alias = 'i' + ) { return $this->em - ->getRepository(Item::class) - ->createQueryBuilder('i'); + ->getRepository($entityClassName) + ->createQueryBuilder($alias); } } diff --git a/Tests/Fixtures/Entity/Item.php b/Tests/Fixtures/Entity/Item.php index fafa90f..b08690a 100644 --- a/Tests/Fixtures/Entity/Item.php +++ b/Tests/Fixtures/Entity/Item.php @@ -26,13 +26,13 @@ class Item protected int $id; #[ORM\Column()] - protected string $name; + protected string $name = ''; #[ORM\Column(type: 'integer')] - protected int $position; + protected ?int $position = null; #[ORM\Column(type: 'boolean')] - protected bool $enabled; + protected bool $enabled = false; #[ORM\Column(type: 'datetime', nullable: true)] protected ?\DateTime $createdAt = null; @@ -41,7 +41,7 @@ class Item protected ?\DateTime $updatedAt = null; #[ORM\OneToMany(targetEntity: Options::class, mappedBy: 'item')] - private array $options; + private array $options = []; public function getId(): int { @@ -58,12 +58,12 @@ public function setName(string $name): void $this->name = $name; } - public function getPosition(): int + public function getPosition(): ?int { return $this->position; } - public function setPosition(int $position): void + public function setPosition(?int $position): void { $this->position = $position; } diff --git a/Tests/Fixtures/Entity/Options.php b/Tests/Fixtures/Entity/Options.php index b28f6fa..81a4074 100644 --- a/Tests/Fixtures/Entity/Options.php +++ b/Tests/Fixtures/Entity/Options.php @@ -25,37 +25,47 @@ class Options protected int $id; #[ORM\Column()] - protected string $label; + protected ?string $label = null; #[ORM\Column(type: 'integer')] - protected int $rank; + protected ?int $rank = null; #[ORM\ManyToOne(targetEntity: Item::class, inversedBy: 'options')] #[ORM\JoinColumn()] - private Item $item; + private ?Item $item = null; public function getId(): int { return $this->id; } - public function getLabel(): string + public function getLabel(): ?string { return $this->label; } - public function setLabel(string $label): void + public function setLabel(?string $label): void { $this->label = $label; } - public function getRank(): int + public function getRank(): ?int { return $this->rank; } - public function setRank(int $rank): void + public function setRank(?int $rank): void { $this->rank = $rank; } + + public function getItem(): ?Item + { + return $this->item; + } + + public function setItem(?Item $item): void + { + $this->item = $item; + } } diff --git a/Tests/Fixtures/Filter/InheritDataFilterType.php b/Tests/Fixtures/Filter/InheritDataFilterType.php new file mode 100644 index 0000000..3503846 --- /dev/null +++ b/Tests/Fixtures/Filter/InheritDataFilterType.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter; + +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\QueryBuilder; +use Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderExecuterInterface; +use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; + +/** + * Form filter for tests. + * + * @author Bart Heyrman + */ +class InheritDataFilterType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('item', ItemFilterType::class, [ + 'add_shared' => function (FilterBuilderExecuterInterface $qbe) { + $closure = function (QueryBuilder $filterBuilder, $alias, $joinAlias, Expr $expr) { + $filterBuilder->leftJoin($alias . '.item', $joinAlias); + }; + + + $qbe->addOnce($qbe->getAlias().'.item', 'item', $closure); + }, + 'data_class' => Item::class, + ]) + ->add('option', OptionFilterType::class, [ + 'inherit_data' => true + ]) + ; + } + + /** + * @return string + */ + public function getBlockPrefix(): string + { + return 'inherit_filter'; + } +} diff --git a/Tests/Fixtures/Filter/ItemFilterType.php b/Tests/Fixtures/Filter/ItemFilterType.php index a36dfc6..7a12ad0 100644 --- a/Tests/Fixtures/Filter/ItemFilterType.php +++ b/Tests/Fixtures/Filter/ItemFilterType.php @@ -17,6 +17,7 @@ use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateFilterType; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeFilterType; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType; +use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\SharedableFilterType; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -49,4 +50,9 @@ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults(['with_selector' => false, 'checkbox' => false, 'datetime' => false, 'disabled_name' => false]); } + + public function getParent(): string + { + return SharedableFilterType::class; // this allows us to use the "add_shared" option + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1d0977e..f5fd44b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,37 +1,37 @@ + - + + + ./Tests/ + + + + + ./ + + + ./Resources + ./Tests + ./vendor + + - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - - - - - - - - + + + + + +