Merge branch '3.4' into 4.4
* 3.4: [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
This commit is contained in:
commit
a379051c82
6
phpunit
6
phpunit
@ -12,7 +12,11 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) {
|
||||
if (false === getenv('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT') && false !== strpos(@file_get_contents(__DIR__.'/src/Symfony/Component/HttpKernel/Kernel.php'), 'const MAJOR_VERSION = 3;')) {
|
||||
putenv('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1');
|
||||
}
|
||||
putenv('SYMFONY_PHPUNIT_VERSION=8.3');
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
putenv('SYMFONY_PHPUNIT_VERSION=9.3');
|
||||
} else {
|
||||
putenv('SYMFONY_PHPUNIT_VERSION=8.3');
|
||||
}
|
||||
} elseif (\PHP_VERSION_ID >= 70000) {
|
||||
putenv('SYMFONY_PHPUNIT_VERSION=6.5');
|
||||
}
|
||||
|
@ -231,13 +231,6 @@ class ViolationMapper implements ViolationMapperInterface
|
||||
// Form inherits its parent data
|
||||
// Cut the piece out of the property path and proceed
|
||||
$propertyPathBuilder->remove($i);
|
||||
} elseif (!$scope->getConfig()->getMapped()) {
|
||||
// Form is not mapped
|
||||
// Set the form as new origin and strip everything
|
||||
// we have so far in the path
|
||||
$origin = $scope;
|
||||
$propertyPathBuilder->remove(0, $i + 1);
|
||||
$i = 0;
|
||||
} else {
|
||||
/* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
|
||||
$propertyPath = $scope->getPropertyPath();
|
||||
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper\Fixtures;
|
||||
|
||||
class Issue
|
||||
{
|
||||
}
|
@ -22,6 +22,7 @@ use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper\Fixtures\Issue;
|
||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
@ -70,12 +71,12 @@ class ViolationMapperTest extends TestCase
|
||||
$this->params = ['foo' => 'bar'];
|
||||
}
|
||||
|
||||
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = [], $inheritData = false, $synchronized = true)
|
||||
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null, $errorMapping = [], $inheritData = false, $synchronized = true, array $options = [])
|
||||
{
|
||||
$config = new FormConfigBuilder($name, $dataClass, $this->dispatcher, [
|
||||
'error_mapping' => $errorMapping,
|
||||
]);
|
||||
$config->setMapped(true);
|
||||
] + $options);
|
||||
$config->setMapped(isset($options['mapped']) ? $options['mapped'] : true);
|
||||
$config->setInheritData($inheritData);
|
||||
$config->setPropertyPath($propertyPath);
|
||||
$config->setCompound(true);
|
||||
@ -91,12 +92,9 @@ class ViolationMapperTest extends TestCase
|
||||
return new Form($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $propertyPath
|
||||
*/
|
||||
protected function getConstraintViolation($propertyPath): ConstraintViolation
|
||||
protected function getConstraintViolation($propertyPath, $root = null): ConstraintViolation
|
||||
{
|
||||
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null);
|
||||
return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, $root, $propertyPath, null);
|
||||
}
|
||||
|
||||
protected function getFormError(ConstraintViolationInterface $violation, FormInterface $form): FormError
|
||||
@ -107,6 +105,33 @@ class ViolationMapperTest extends TestCase
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function testMappingErrorsWhenFormIsNotMapped()
|
||||
{
|
||||
$form = $this->getForm('name', null, Issue::class, [
|
||||
'child1' => 'child2',
|
||||
]);
|
||||
|
||||
$violation = $this->getConstraintViolation('children[child1].data', $form);
|
||||
|
||||
$child1Form = $this->getForm('child1', null, null, [], false, true, [
|
||||
'mapped' => false,
|
||||
]);
|
||||
$child2Form = $this->getForm('child2', null, null, [], false, true, [
|
||||
'mapped' => false,
|
||||
]);
|
||||
|
||||
$form->add($child1Form);
|
||||
$form->add($child2Form);
|
||||
|
||||
$form->submit([]);
|
||||
|
||||
$this->mapper->mapViolation($violation, $form);
|
||||
|
||||
$this->assertCount(0, $form->getErrors());
|
||||
$this->assertCount(0, $form->get('child1')->getErrors());
|
||||
$this->assertCount(1, $form->get('child2')->getErrors());
|
||||
}
|
||||
|
||||
public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
|
||||
{
|
||||
$violation = $this->getConstraintViolation('children[address].data.foo');
|
||||
|
@ -136,6 +136,17 @@ abstract class Composite extends Constraint
|
||||
*/
|
||||
abstract protected function getCompositeOption();
|
||||
|
||||
/**
|
||||
* @internal Used by metadata
|
||||
*
|
||||
* @return Constraint[]
|
||||
*/
|
||||
public function getNestedContraints()
|
||||
{
|
||||
/* @var Constraint[] $nestedConstraints */
|
||||
return $this->{$this->getCompositeOption()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the nested constraints.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Validator\Mapping;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
use Symfony\Component\Validator\Constraints\Traverse;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
@ -173,9 +174,7 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
|
||||
*/
|
||||
public function addConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets())) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
|
||||
}
|
||||
$this->checkConstraint($constraint);
|
||||
|
||||
if ($constraint instanceof Traverse) {
|
||||
if ($constraint->traverse) {
|
||||
@ -487,4 +486,17 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
|
||||
|
||||
$this->members[$property][] = $metadata;
|
||||
}
|
||||
|
||||
private function checkConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets(), true)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
|
||||
}
|
||||
|
||||
if ($constraint instanceof Composite) {
|
||||
foreach ($constraint->getNestedContraints() as $nestedContraint) {
|
||||
$this->checkConstraint($nestedContraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Validator\Mapping;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
@ -71,9 +72,7 @@ abstract class MemberMetadata extends GenericMetadata implements PropertyMetadat
|
||||
*/
|
||||
public function addConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets())) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', \get_class($constraint)));
|
||||
}
|
||||
$this->checkConstraint($constraint);
|
||||
|
||||
parent::addConstraint($constraint);
|
||||
|
||||
@ -181,4 +180,17 @@ abstract class MemberMetadata extends GenericMetadata implements PropertyMetadat
|
||||
* @return \ReflectionMethod|\ReflectionProperty The reflection instance
|
||||
*/
|
||||
abstract protected function newReflectionMember($objectOrClassName);
|
||||
|
||||
private function checkConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets(), true)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', \get_class($constraint)));
|
||||
}
|
||||
|
||||
if ($constraint instanceof Composite) {
|
||||
foreach ($constraint->getNestedContraints() as $nestedContraint) {
|
||||
$this->checkConstraint($nestedContraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ namespace Symfony\Component\Validator\Tests\Mapping;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
|
||||
@ -52,6 +55,20 @@ class ClassMetadataTest extends TestCase
|
||||
$this->metadata->addConstraint(new PropertyConstraint());
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsNestedPropertyConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint" cannot be put on classes.');
|
||||
|
||||
$this->metadata->addConstraint(new ClassCompositeConstraint([new PropertyConstraint()]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsNestedClassConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new ClassCompositeConstraint([new ClassConstraint()]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testAddPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addPropertyConstraint('firstName', new ConstraintA());
|
||||
@ -311,3 +328,23 @@ class ClassMetadataTest extends TestCase
|
||||
$this->assertCount(0, $this->metadata->getPropertyMetadata('foo'), '->getPropertyMetadata() returns an empty collection if no metadata is configured for the given property');
|
||||
}
|
||||
}
|
||||
|
||||
class ClassCompositeConstraint extends Composite
|
||||
{
|
||||
public $nested;
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
return $this->getCompositeOption();
|
||||
}
|
||||
|
||||
protected function getCompositeOption()
|
||||
{
|
||||
return 'nested';
|
||||
}
|
||||
|
||||
public function getTargets()
|
||||
{
|
||||
return [self::CLASS_CONSTRAINT];
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,16 @@
|
||||
namespace Symfony\Component\Validator\Tests\Mapping;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraints\Collection;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\Required;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Mapping\MemberMetadata;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
|
||||
|
||||
class MemberMetadataTest extends TestCase
|
||||
{
|
||||
@ -43,6 +48,34 @@ class MemberMetadataTest extends TestCase
|
||||
$this->metadata->addConstraint(new ClassConstraint());
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsNestedClassConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
|
||||
|
||||
$this->metadata->addConstraint(new PropertyCompositeConstraint([new ClassConstraint()]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsDeepNestedClassConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
|
||||
|
||||
$this->metadata->addConstraint(new Collection(['field1' => new Required([new ClassConstraint()])]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsNestedPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new PropertyCompositeConstraint([new PropertyConstraint()]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsDeepNestedPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new Collection(['field1' => new Required([new PropertyConstraint()])]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testSerialize()
|
||||
{
|
||||
$this->metadata->addConstraint(new ConstraintA(['property1' => 'A']));
|
||||
@ -82,3 +115,18 @@ class TestMemberMetadata extends MemberMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyCompositeConstraint extends Composite
|
||||
{
|
||||
public $nested;
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
return $this->getCompositeOption();
|
||||
}
|
||||
|
||||
protected function getCompositeOption()
|
||||
{
|
||||
return 'nested';
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +176,12 @@ class Parser
|
||||
$this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags)
|
||||
);
|
||||
} else {
|
||||
if (isset($values['leadspaces'])
|
||||
&& self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
|
||||
if (
|
||||
isset($values['leadspaces'])
|
||||
&& (
|
||||
'!' === $values['value'][0]
|
||||
|| self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
|
||||
)
|
||||
) {
|
||||
// this is a compact notation element, add to next block and parse
|
||||
$block = $values['value'];
|
||||
|
@ -2077,6 +2077,34 @@ YAML;
|
||||
$this->parser->parse('!php/const:App\Kernel::SEMART_VERSION', Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_CONSTANT);
|
||||
}
|
||||
|
||||
public function testPhpConstantTagMappingAsScalarKey()
|
||||
{
|
||||
$yaml = <<<YAML
|
||||
map1:
|
||||
- foo: 'value_0'
|
||||
!php/const 'Symfony\Component\Yaml\Tests\B::BAR': 'value_1'
|
||||
map2:
|
||||
- !php/const 'Symfony\Component\Yaml\Tests\B::FOO': 'value_0'
|
||||
bar: 'value_1'
|
||||
YAML;
|
||||
$this->assertSame([
|
||||
'map1' => [['foo' => 'value_0', 'bar' => 'value_1']],
|
||||
'map2' => [['foo' => 'value_0', 'bar' => 'value_1']],
|
||||
], $this->parser->parse($yaml, Yaml::PARSE_CONSTANT));
|
||||
}
|
||||
|
||||
public function testTagMappingAsScalarKey()
|
||||
{
|
||||
$yaml = <<<YAML
|
||||
map1:
|
||||
- !!str 0: 'value_0'
|
||||
!!str 1: 'value_1'
|
||||
YAML;
|
||||
$this->assertSame([
|
||||
'map1' => [['0' => 'value_0', '1' => 'value_1']],
|
||||
], $this->parser->parse($yaml));
|
||||
}
|
||||
|
||||
public function testMergeKeysWhenMappingsAreParsedAsObjects()
|
||||
{
|
||||
$yaml = <<<YAML
|
||||
@ -2339,7 +2367,7 @@ YAML;
|
||||
parameters:
|
||||
abc
|
||||
|
||||
# Comment
|
||||
# Comment
|
||||
YAML;
|
||||
|
||||
$this->assertSame(['parameters' => 'abc'], $this->parser->parse($yaml));
|
||||
|
Reference in New Issue
Block a user