Skip to content

Commit 7aaaf5c

Browse files
Add support for Symfony Form inherit_data (#34)
1 parent 87426de commit 7aaaf5c

File tree

8 files changed

+163
-53
lines changed

8 files changed

+163
-53
lines changed

Filter/FilterBuilderUpdater.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,11 @@ protected function addFilters(FormInterface $form, QueryInterface $filterQuery,
161161
} elseif ($formType instanceof EmbeddedFilterTypeInterface) {
162162
$this->addFilters($child, $filterQuery, $child->getConfig()->getAttribute('filter_field_name') ?? ($alias . '.' . $child->getName()));
163163

164-
// default case
164+
// inherit_data set to true
165+
} elseif ($child->getConfig()->getInheritData()) {
166+
$this->addFilters($child, $filterQuery, $alias);
167+
168+
// default case
165169
} else {
166170
$condition = $this->getFilterCondition($child, $formType, $filterQuery, $alias);
167171

@@ -194,7 +198,11 @@ protected function getFilterCondition(FormInterface $form, AbstractType $formTyp
194198
$parentForm = $form;
195199
do {
196200
$parentForm = $parentForm->getParent();
197-
if (!is_numeric($parentForm->getName()) && $parentForm->getConfig()->getMapped()) { // skip collection numeric index and not mapped fields
201+
if (
202+
!is_numeric($parentForm->getName())
203+
&& $parentForm->getConfig()->getMapped()
204+
&& !$parentForm->getConfig()->getInheritData()
205+
) { // skip collection numeric index and not mapped fields and inherited data
198206
$completeName = $parentForm->getName() . '.' . $completeName;
199207
}
200208
} while (!$parentForm->isRoot());
@@ -295,6 +303,11 @@ protected function buildDefaultConditionNode(Form $form, ConditionNodeInterface
295303
$root->andX(),
296304
$name
297305
);
306+
} elseif ($child->getConfig()->getInheritData()) {
307+
$this->buildDefaultConditionNode(
308+
$child,
309+
$root
310+
);
298311
} else {
299312
$root->field($name);
300313
}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ Please consider [opening a question on StackOverflow](http://stackoverflow.com/q
121121

122122
Github Issues are dedicated to bug reports and feature requests.
123123

124-
Symfony 2.8 and 3.4
125-
-------------------
124+
For compatibility with Symfony 2.8 and 3.4
125+
------------------------------------------
126126

127127
Please use last tag v5.*
128128

Tests/Filter/Doctrine/ORMQueryBuilderUpdaterTest.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
use Spiriit\Bundle\FormFilterBundle\Filter\Condition\ConditionBuilderInterface;
1515
use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item;
16+
use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Options;
17+
use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter\InheritDataFilterType;
1618
use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter\ItemEmbeddedOptionsFilterType;
1719

1820
/**
@@ -177,10 +179,34 @@ public function testWithDataClass()
177179
$this->assertEquals(['p_opt_rank' => 6], $this->getQueryBuilderParameters($doctrineQueryBuilder));
178180
}
179181

180-
protected function createDoctrineQueryBuilder()
182+
public function testWithInheritDataFormOption()
181183
{
184+
// doctrine query builder without any joins + a data_class
185+
$form = $this->formFactory->create(InheritDataFilterType::class, null, ['data_class' => Options::class]);
186+
$filterQueryBuilder = $this->initQueryBuilderUpdater();
187+
188+
$doctrineQueryBuilder = $this->createDoctrineQueryBuilder(Options::class, 'o');
189+
190+
$form->submit(['option' => ['label' => 'dude', 'rank' => 1], 'item' => ['name' => 'blabla', 'position' => 2, 'enabled' => 'y']]);
191+
192+
$expectedDql = 'SELECT o FROM Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Options o LEFT JOIN o.item item';
193+
$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)';
194+
$filterQueryBuilder->addFilterConditions($form, $doctrineQueryBuilder);
195+
196+
$this->assertEquals($expectedDql, $doctrineQueryBuilder->getDql());
197+
$this->assertEquals([
198+
'p_o_rank' => 1.0,
199+
'p_item_position' => 2.0,
200+
'p_item_enabled' => true,
201+
], $this->getQueryBuilderParameters($doctrineQueryBuilder));
202+
}
203+
204+
protected function createDoctrineQueryBuilder(
205+
string $entityClassName = Item::class,
206+
string $alias = 'i'
207+
) {
182208
return $this->em
183-
->getRepository(Item::class)
184-
->createQueryBuilder('i');
209+
->getRepository($entityClassName)
210+
->createQueryBuilder($alias);
185211
}
186212
}

Tests/Fixtures/Entity/Item.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ class Item
2626
protected int $id;
2727

2828
#[ORM\Column()]
29-
protected string $name;
29+
protected string $name = '';
3030

3131
#[ORM\Column(type: 'integer')]
32-
protected int $position;
32+
protected ?int $position = null;
3333

3434
#[ORM\Column(type: 'boolean')]
35-
protected bool $enabled;
35+
protected bool $enabled = false;
3636

3737
#[ORM\Column(type: 'datetime', nullable: true)]
3838
protected ?\DateTime $createdAt = null;
@@ -41,7 +41,7 @@ class Item
4141
protected ?\DateTime $updatedAt = null;
4242

4343
#[ORM\OneToMany(targetEntity: Options::class, mappedBy: 'item')]
44-
private array $options;
44+
private array $options = [];
4545

4646
public function getId(): int
4747
{
@@ -58,12 +58,12 @@ public function setName(string $name): void
5858
$this->name = $name;
5959
}
6060

61-
public function getPosition(): int
61+
public function getPosition(): ?int
6262
{
6363
return $this->position;
6464
}
6565

66-
public function setPosition(int $position): void
66+
public function setPosition(?int $position): void
6767
{
6868
$this->position = $position;
6969
}

Tests/Fixtures/Entity/Options.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,37 +25,47 @@ class Options
2525
protected int $id;
2626

2727
#[ORM\Column()]
28-
protected string $label;
28+
protected ?string $label = null;
2929

3030
#[ORM\Column(type: 'integer')]
31-
protected int $rank;
31+
protected ?int $rank = null;
3232

3333
#[ORM\ManyToOne(targetEntity: Item::class, inversedBy: 'options')]
3434
#[ORM\JoinColumn()]
35-
private Item $item;
35+
private ?Item $item = null;
3636

3737
public function getId(): int
3838
{
3939
return $this->id;
4040
}
4141

42-
public function getLabel(): string
42+
public function getLabel(): ?string
4343
{
4444
return $this->label;
4545
}
4646

47-
public function setLabel(string $label): void
47+
public function setLabel(?string $label): void
4848
{
4949
$this->label = $label;
5050
}
5151

52-
public function getRank(): int
52+
public function getRank(): ?int
5353
{
5454
return $this->rank;
5555
}
5656

57-
public function setRank(int $rank): void
57+
public function setRank(?int $rank): void
5858
{
5959
$this->rank = $rank;
6060
}
61+
62+
public function getItem(): ?Item
63+
{
64+
return $this->item;
65+
}
66+
67+
public function setItem(?Item $item): void
68+
{
69+
$this->item = $item;
70+
}
6171
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the composer-write-changelogs project.
5+
*
6+
* (c) Dev Spiriit <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Filter;
13+
14+
use Doctrine\ORM\Query\Expr;
15+
use Doctrine\ORM\QueryBuilder;
16+
use Spiriit\Bundle\FormFilterBundle\Filter\FilterBuilderExecuterInterface;
17+
use Spiriit\Bundle\FormFilterBundle\Tests\Fixtures\Entity\Item;
18+
use Symfony\Component\Form\AbstractType;
19+
use Symfony\Component\Form\FormBuilderInterface;
20+
21+
/**
22+
* Form filter for tests.
23+
*
24+
* @author Bart Heyrman <[email protected]>
25+
*/
26+
class InheritDataFilterType extends AbstractType
27+
{
28+
public function buildForm(FormBuilderInterface $builder, array $options): void
29+
{
30+
$builder
31+
->add('item', ItemFilterType::class, [
32+
'add_shared' => function (FilterBuilderExecuterInterface $qbe) {
33+
$closure = function (QueryBuilder $filterBuilder, $alias, $joinAlias, Expr $expr) {
34+
$filterBuilder->leftJoin($alias . '.item', $joinAlias);
35+
};
36+
37+
38+
$qbe->addOnce($qbe->getAlias().'.item', 'item', $closure);
39+
},
40+
'data_class' => Item::class,
41+
])
42+
->add('option', OptionFilterType::class, [
43+
'inherit_data' => true
44+
])
45+
;
46+
}
47+
48+
/**
49+
* @return string
50+
*/
51+
public function getBlockPrefix(): string
52+
{
53+
return 'inherit_filter';
54+
}
55+
}

Tests/Fixtures/Filter/ItemFilterType.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateFilterType;
1818
use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\DateTimeFilterType;
1919
use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType;
20+
use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\SharedableFilterType;
2021
use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType;
2122
use Symfony\Component\Form\AbstractType;
2223
use Symfony\Component\Form\FormBuilderInterface;
@@ -49,4 +50,9 @@ public function configureOptions(OptionsResolver $resolver): void
4950
{
5051
$resolver->setDefaults(['with_selector' => false, 'checkbox' => false, 'datetime' => false, 'disabled_name' => false]);
5152
}
53+
54+
public function getParent(): string
55+
{
56+
return SharedableFilterType::class; // this allows us to use the "add_shared" option
57+
}
5258
}

phpunit.xml.dist

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
backupGlobals="false"
5+
backupStaticAttributes="false"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
bootstrap="vendor/autoload.php"
12+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
13+
>
214

3-
<phpunit backupGlobals="false"
4-
backupStaticAttributes="false"
5-
convertErrorsToExceptions="true"
6-
convertNoticesToExceptions="true"
7-
convertWarningsToExceptions="true"
8-
processIsolation="false"
9-
stopOnFailure="false"
10-
bootstrap="vendor/autoload.php"
11-
>
15+
<testsuites>
16+
<testsuite name="SpiriitFormFilterBundle Test Suite">
17+
<directory>./Tests/</directory>
18+
</testsuite>
19+
</testsuites>
20+
<coverage>
21+
<include>
22+
<directory>./</directory>
23+
</include>
24+
<exclude>
25+
<directory>./Resources</directory>
26+
<directory>./Tests</directory>
27+
<directory>./vendor</directory>
28+
</exclude>
29+
</coverage>
1230

13-
<testsuites>
14-
<testsuite name="SpiriitFormFilterBundle Test Suite">
15-
<directory>./Tests/</directory>
16-
</testsuite>
17-
</testsuites>
18-
<filter>
19-
20-
<whitelist>
21-
<directory>./</directory>
22-
<exclude>
23-
<directory>./Resources</directory>
24-
<directory>./Tests</directory>
25-
<directory>./vendor</directory>
26-
</exclude>
27-
</whitelist>
28-
</filter>
29-
30-
<php>
31-
<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"></env>
32-
</php>
33-
34-
<listeners>
35-
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
36-
</listeners>
31+
<php>
32+
<env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/>
33+
</php>
34+
<listeners>
35+
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
36+
</listeners>
3737
</phpunit>

0 commit comments

Comments
 (0)