Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b0fdc9

Browse files
committed
Merge branch '4.4' into 5.1
* 4.4: [Validator] RangeTest: fix expected deprecation [Yaml] Fix for #36624; Allow PHP constant as first key in block Use PHPUnit 9.3 on php 8. fix mapping errors from unmapped forms [Validator] Add target guards for Composite nested constraints
2 parents 5afac1d + a379051 commit 2b0fdc9

File tree

12 files changed

+216
-26
lines changed

12 files changed

+216
-26
lines changed

phpunit

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) {
1212
if (false === getenv('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT') && false !== strpos(@file_get_contents(__DIR__.'/src/Symfony/Component/HttpKernel/Kernel.php'), 'const MAJOR_VERSION = 3;')) {
1313
putenv('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1');
1414
}
15-
putenv('SYMFONY_PHPUNIT_VERSION=8.3');
15+
if (\PHP_VERSION_ID >= 80000) {
16+
putenv('SYMFONY_PHPUNIT_VERSION=9.3');
17+
} else {
18+
putenv('SYMFONY_PHPUNIT_VERSION=8.3');
19+
}
1620
} elseif (\PHP_VERSION_ID >= 70000) {
1721
putenv('SYMFONY_PHPUNIT_VERSION=6.5');
1822
}

src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,6 @@ private function reconstructPath(ViolationPath $violationPath, FormInterface $or
231231
// Form inherits its parent data
232232
// Cut the piece out of the property path and proceed
233233
$propertyPathBuilder->remove($i);
234-
} elseif (!$scope->getConfig()->getMapped()) {
235-
// Form is not mapped
236-
// Set the form as new origin and strip everything
237-
// we have so far in the path
238-
$origin = $scope;
239-
$propertyPathBuilder->remove(0, $i + 1);
240-
$i = 0;
241234
} else {
242235
/* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
243236
$propertyPath = $scope->getPropertyPath();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[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 Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper\Fixtures;
13+
14+
class Issue
15+
{
16+
}

src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\Form\FormConfigBuilder;
2323
use Symfony\Component\Form\FormError;
2424
use Symfony\Component\Form\FormInterface;
25+
use Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper\Fixtures\Issue;
2526
use Symfony\Component\PropertyAccess\PropertyPath;
2627
use Symfony\Component\Validator\ConstraintViolation;
2728
use Symfony\Component\Validator\ConstraintViolationInterface;
@@ -70,12 +71,12 @@ protected function setUp(): void
7071
$this->params = ['foo' => 'bar'];
7172
}
7273

73-
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = [], $inheritData = false, $synchronized = true)
74+
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = [], $inheritData = false, $synchronized = true, array $options = [])
7475
{
7576
$config = new FormConfigBuilder($name, $dataClass, $this->dispatcher, [
7677
'error_mapping' => $errorMapping,
77-
]);
78-
$config->setMapped(true);
78+
] + $options);
79+
$config->setMapped(isset($options['mapped']) ? $options['mapped'] : true);
7980
$config->setInheritData($inheritData);
8081
$config->setPropertyPath($propertyPath);
8182
$config->setCompound(true);
@@ -91,12 +92,9 @@ function () { throw new TransformationFailedException(); }
9192
return new Form($config);
9293
}
9394

94-
/**
95-
* @param $propertyPath
96-
*/
97-
protected function getConstraintViolation($propertyPath): ConstraintViolation
95+
protected function getConstraintViolation($propertyPath, $root = null): ConstraintViolation
9896
{
99-
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null);
97+
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, $root, $propertyPath, null);
10098
}
10199

102100
protected function getFormError(ConstraintViolationInterface $violation, FormInterface $form): FormError
@@ -107,6 +105,33 @@ protected function getFormError(ConstraintViolationInterface $violation, FormInt
107105
return $error;
108106
}
109107

108+
public function testMappingErrorsWhenFormIsNotMapped()
109+
{
110+
$form = $this->getForm('name', null, Issue::class, [
111+
'child1' => 'child2',
112+
]);
113+
114+
$violation = $this->getConstraintViolation('children[child1].data', $form);
115+
116+
$child1Form = $this->getForm('child1', null, null, [], false, true, [
117+
'mapped' => false,
118+
]);
119+
$child2Form = $this->getForm('child2', null, null, [], false, true, [
120+
'mapped' => false,
121+
]);
122+
123+
$form->add($child1Form);
124+
$form->add($child2Form);
125+
126+
$form->submit([]);
127+
128+
$this->mapper->mapViolation($violation, $form);
129+
130+
$this->assertCount(0, $form->getErrors());
131+
$this->assertCount(0, $form->get('child1')->getErrors());
132+
$this->assertCount(1, $form->get('child2')->getErrors());
133+
}
134+
110135
public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
111136
{
112137
$violation = $this->getConstraintViolation('children[address].data.foo');

src/Symfony/Component/Validator/Constraints/Composite.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ public function addImplicitGroupName($group)
136136
*/
137137
abstract protected function getCompositeOption();
138138

139+
/**
140+
* @internal Used by metadata
141+
*
142+
* @return Constraint[]
143+
*/
144+
public function getNestedContraints()
145+
{
146+
/* @var Constraint[] $nestedConstraints */
147+
return $this->{$this->getCompositeOption()};
148+
}
149+
139150
/**
140151
* Initializes the nested constraints.
141152
*

src/Symfony/Component/Validator/Mapping/ClassMetadata.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Mapping;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Constraints\Composite;
1516
use Symfony\Component\Validator\Constraints\GroupSequence;
1617
use Symfony\Component\Validator\Constraints\Traverse;
1718
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
@@ -173,9 +174,7 @@ public function getDefaultGroup()
173174
*/
174175
public function addConstraint(Constraint $constraint)
175176
{
176-
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets())) {
177-
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', get_debug_type($constraint)));
178-
}
177+
$this->checkConstraint($constraint);
179178

180179
if ($constraint instanceof Traverse) {
181180
if ($constraint->traverse) {
@@ -474,4 +473,17 @@ private function addPropertyMetadata(PropertyMetadataInterface $metadata)
474473

475474
$this->members[$property][] = $metadata;
476475
}
476+
477+
private function checkConstraint(Constraint $constraint)
478+
{
479+
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets(), true)) {
480+
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', get_debug_type($constraint)));
481+
}
482+
483+
if ($constraint instanceof Composite) {
484+
foreach ($constraint->getNestedContraints() as $nestedContraint) {
485+
$this->checkConstraint($nestedContraint);
486+
}
487+
}
488+
}
477489
}

src/Symfony/Component/Validator/Mapping/MemberMetadata.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Mapping;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Constraints\Composite;
1516
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1617

1718
/**
@@ -71,9 +72,7 @@ public function __construct(string $class, string $name, string $property)
7172
*/
7273
public function addConstraint(Constraint $constraint)
7374
{
74-
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets())) {
75-
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', get_debug_type($constraint)));
76-
}
75+
$this->checkConstraint($constraint);
7776

7877
parent::addConstraint($constraint);
7978

@@ -181,4 +180,17 @@ public function getReflectionMember($objectOrClassName)
181180
* @return \ReflectionMethod|\ReflectionProperty The reflection instance
182181
*/
183182
abstract protected function newReflectionMember($objectOrClassName);
183+
184+
private function checkConstraint(Constraint $constraint)
185+
{
186+
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets(), true)) {
187+
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', get_debug_type($constraint)));
188+
}
189+
190+
if ($constraint instanceof Composite) {
191+
foreach ($constraint->getNestedContraints() as $nestedContraint) {
192+
$this->checkConstraint($nestedContraint);
193+
}
194+
}
195+
}
184196
}

src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function provideDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet(
5252

5353
/**
5454
* @group legacy
55-
* @expectedDeprecation Since symfony/validator 4.4: minMessage and maxMessage are deprecated when min and max options are set together. Use notInRangeMessage instead.
55+
* @expectedDeprecation Since symfony/validator 4.4: "minMessage" and "maxMessage" are deprecated when the "min" and "max" options are both set. Use "notInRangeMessage" instead.
5656
* @dataProvider provideDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet
5757
*/
5858
public function testDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet(array $options, bool $expectedDeprecatedMinMessageSet, bool $expectedDeprecatedMaxMessageSet)

src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Validator\Constraint;
16+
use Symfony\Component\Validator\Constraints\Composite;
1617
use Symfony\Component\Validator\Constraints\Valid;
18+
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1719
use Symfony\Component\Validator\Mapping\ClassMetadata;
20+
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
1821
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
1922
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
2023
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
@@ -52,6 +55,20 @@ public function testAddConstraintRequiresClassConstraints()
5255
$this->metadata->addConstraint(new PropertyConstraint());
5356
}
5457

58+
public function testAddCompositeConstraintRejectsNestedPropertyConstraints()
59+
{
60+
$this->expectException(ConstraintDefinitionException::class);
61+
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint" cannot be put on classes.');
62+
63+
$this->metadata->addConstraint(new ClassCompositeConstraint([new PropertyConstraint()]));
64+
}
65+
66+
public function testAddCompositeConstraintAcceptsNestedClassConstraints()
67+
{
68+
$this->metadata->addConstraint($constraint = new ClassCompositeConstraint([new ClassConstraint()]));
69+
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
70+
}
71+
5572
public function testAddPropertyConstraints()
5673
{
5774
$this->metadata->addPropertyConstraint('firstName', new ConstraintA());
@@ -311,3 +328,23 @@ public function testGetPropertyMetadataReturnsEmptyArrayWithoutConfiguredMetadat
311328
$this->assertCount(0, $this->metadata->getPropertyMetadata('foo'), '->getPropertyMetadata() returns an empty collection if no metadata is configured for the given property');
312329
}
313330
}
331+
332+
class ClassCompositeConstraint extends Composite
333+
{
334+
public $nested;
335+
336+
public function getDefaultOption()
337+
{
338+
return $this->getCompositeOption();
339+
}
340+
341+
protected function getCompositeOption()
342+
{
343+
return 'nested';
344+
}
345+
346+
public function getTargets()
347+
{
348+
return [self::CLASS_CONSTRAINT];
349+
}
350+
}

src/Symfony/Component/Validator/Tests/Mapping/MemberMetadataTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
namespace Symfony\Component\Validator\Tests\Mapping;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Validator\Constraints\Collection;
16+
use Symfony\Component\Validator\Constraints\Composite;
17+
use Symfony\Component\Validator\Constraints\Required;
1518
use Symfony\Component\Validator\Constraints\Valid;
19+
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1620
use Symfony\Component\Validator\Mapping\MemberMetadata;
1721
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
1822
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
1923
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
24+
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
2025

2126
class MemberMetadataTest extends TestCase
2227
{
@@ -43,6 +48,34 @@ public function testAddConstraintRequiresClassConstraints()
4348
$this->metadata->addConstraint(new ClassConstraint());
4449
}
4550

51+
public function testAddCompositeConstraintRejectsNestedClassConstraints()
52+
{
53+
$this->expectException(ConstraintDefinitionException::class);
54+
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
55+
56+
$this->metadata->addConstraint(new PropertyCompositeConstraint([new ClassConstraint()]));
57+
}
58+
59+
public function testAddCompositeConstraintRejectsDeepNestedClassConstraints()
60+
{
61+
$this->expectException(ConstraintDefinitionException::class);
62+
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
63+
64+
$this->metadata->addConstraint(new Collection(['field1' => new Required([new ClassConstraint()])]));
65+
}
66+
67+
public function testAddCompositeConstraintAcceptsNestedPropertyConstraints()
68+
{
69+
$this->metadata->addConstraint($constraint = new PropertyCompositeConstraint([new PropertyConstraint()]));
70+
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
71+
}
72+
73+
public function testAddCompositeConstraintAcceptsDeepNestedPropertyConstraints()
74+
{
75+
$this->metadata->addConstraint($constraint = new Collection(['field1' => new Required([new PropertyConstraint()])]));
76+
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
77+
}
78+
4679
public function testSerialize()
4780
{
4881
$this->metadata->addConstraint(new ConstraintA(['property1' => 'A']));
@@ -82,3 +115,18 @@ protected function newReflectionMember($object): object
82115
{
83116
}
84117
}
118+
119+
class PropertyCompositeConstraint extends Composite
120+
{
121+
public $nested;
122+
123+
public function getDefaultOption()
124+
{
125+
return $this->getCompositeOption();
126+
}
127+
128+
protected function getCompositeOption()
129+
{
130+
return 'nested';
131+
}
132+
}

src/Symfony/Component/Yaml/Parser.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,12 @@ private function doParse(string $value, int $flags)
179179
$this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags)
180180
);
181181
} else {
182-
if (isset($values['leadspaces'])
183-
&& self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
182+
if (
183+
isset($values['leadspaces'])
184+
&& (
185+
'!' === $values['value'][0]
186+
|| self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
187+
)
184188
) {
185189
// this is a compact notation element, add to next block and parse
186190
$block = $values['value'];

0 commit comments

Comments
 (0)