Skip to content

Commit 655455d

Browse files
authored
Merge pull request misd-service-development#194 from odolbeau/prevent-trigger-update-on-form
fix(form): avoid update triggered by new PhoneNumber instance with equal value
2 parents 7f83dd0 + d61c49d commit 655455d

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony2 PhoneNumberBundle.
7+
*
8+
* (c) University of Cambridge
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Misd\PhoneNumberBundle\Form\Extension;
15+
16+
use libphonenumber\PhoneNumber;
17+
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
18+
use Symfony\Component\Form\AbstractTypeExtension;
19+
use Symfony\Component\Form\FormBuilderInterface;
20+
use Symfony\Component\Form\FormEvent;
21+
use Symfony\Component\Form\FormEvents;
22+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
23+
24+
class PhoneNumberTypeEqualityExtension extends AbstractTypeExtension
25+
{
26+
private PropertyAccessorInterface $propertyAccessor;
27+
28+
public function __construct(
29+
PropertyAccessorInterface $propertyAccessor,
30+
) {
31+
$this->propertyAccessor = $propertyAccessor;
32+
}
33+
34+
public static function getExtendedTypes(): iterable
35+
{
36+
return [PhoneNumberType::class];
37+
}
38+
39+
public function buildForm(FormBuilderInterface $builder, array $options): void
40+
{
41+
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
42+
$newPhoneNumber = $event->getData();
43+
44+
$parentForm = $event->getForm()->getParent();
45+
$propertyName = $event->getForm()->getName();
46+
47+
if (!$parentForm) {
48+
return;
49+
}
50+
51+
$original = $parentForm->getData();
52+
if (!$original || !$propertyName) {
53+
return;
54+
}
55+
56+
if ($this->propertyAccessor->isReadable($original, $propertyName)) {
57+
$originalPhoneNumber = $this->propertyAccessor->getValue($original, $propertyName);
58+
} else {
59+
trigger_deprecation('odolbeau/phone-number-bundle', '4.2', 'Could not access property "%s" on class "%s". Make sure it is readable or add a getter method.', $propertyName, $original::class);
60+
61+
return;
62+
}
63+
64+
if ($newPhoneNumber instanceof PhoneNumber && $originalPhoneNumber instanceof PhoneNumber && $newPhoneNumber->equals($originalPhoneNumber)) {
65+
$event->setData($originalPhoneNumber);
66+
}
67+
});
68+
}
69+
}

src/Resources/config/form.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
<service id="Misd\PhoneNumberBundle\Form\Type\PhoneNumberType">
99
<tag name="form.type" alias="phone_number"/>
1010
</service>
11+
12+
<service id="Misd\PhoneNumberBundle\Form\Extension\PhoneNumberTypeEqualityExtension">
13+
<tag name="form.type_extension" extended-type="Misd\PhoneNumberBundle\Form\Type\PhoneNumberType"/>
14+
<argument type="service" id="form.property_accessor" />
15+
</service>
1116
</services>
1217

1318
</container>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony2 PhoneNumberBundle.
7+
*
8+
* (c) University of Cambridge
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Misd\PhoneNumberBundle\Tests\Form\Extension;
15+
16+
use libphonenumber\PhoneNumber;
17+
use Misd\PhoneNumberBundle\Form\Extension\PhoneNumberTypeEqualityExtension;
18+
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
19+
use Symfony\Component\Form\Extension\Core\Type\FormType;
20+
use Symfony\Component\Form\Test\TypeTestCase;
21+
use Symfony\Component\PropertyAccess\PropertyAccess;
22+
23+
class PhoneNumberTypeEqualityExtensionTest extends TypeTestCase
24+
{
25+
protected function getTypeExtensions(): array
26+
{
27+
$accessor = PropertyAccess::createPropertyAccessor();
28+
29+
return [
30+
new PhoneNumberTypeEqualityExtension($accessor),
31+
];
32+
}
33+
34+
public function testNoChangeKeepsOriginalInstance(): void
35+
{
36+
$phone = new PhoneNumber();
37+
$phone->setCountryCode(33);
38+
$phone->setNationalNumber('612345678');
39+
40+
$entity = new class($phone) {
41+
private PhoneNumber $phoneNumber;
42+
43+
public function __construct(PhoneNumber $phoneNumber)
44+
{
45+
$this->phoneNumber = $phoneNumber;
46+
}
47+
48+
public function getPhoneNumber(): PhoneNumber
49+
{
50+
return $this->phoneNumber;
51+
}
52+
53+
public function setPhoneNumber(PhoneNumber $phoneNumber): void
54+
{
55+
$this->phoneNumber = $phoneNumber;
56+
}
57+
};
58+
59+
$form = $this->factory->createBuilder(FormType::class, $entity)
60+
->add('phoneNumber', PhoneNumberType::class, [
61+
'number_type' => PhoneNumberType::NUMBER_TYPE_TEL,
62+
])
63+
->getForm();
64+
65+
$form->submit(['phoneNumber' => '+33612345678']);
66+
67+
$this->assertSame($entity->getPhoneNumber(), $phone);
68+
}
69+
}

0 commit comments

Comments
 (0)