Merge branch '3.4' into 4.4
* 3.4: [Filesystem] Handle paths on different drives [WebProfiler] Do not add src-elem CSP directives if they do not exist [Yaml] fix parse error when unindented collections contain a comment [3.4][Inflector] Improve testSingularize() argument name [PhpUnitBridge] fix PHP 5.3 compat again Skip validation when email is an empty object fix sr_Latn translation [Validator] fix lazy property usage. Fix annotation [PhpUnitBridge] fix compat with PHP 5.3 [DX] Show the ParseException message in YAML file loaders
This commit is contained in:
commit
394946de47
@ -129,12 +129,11 @@ class ContentSecurityPolicyHandler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isset($headers[$header][$type])) {
|
if (!isset($headers[$header][$type])) {
|
||||||
if (isset($headers[$header]['default-src'])) {
|
if (null === $fallback = $this->getDirectiveFallback($directives, $type)) {
|
||||||
$headers[$header][$type] = $headers[$header]['default-src'];
|
|
||||||
} else {
|
|
||||||
// If there is no script-src/style-src and no default-src, no additional rules required.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$headers[$header][$type] = $fallback;
|
||||||
}
|
}
|
||||||
$ruleIsSet = true;
|
$ruleIsSet = true;
|
||||||
if (!\in_array('\'unsafe-inline\'', $headers[$header][$type], true)) {
|
if (!\in_array('\'unsafe-inline\'', $headers[$header][$type], true)) {
|
||||||
@ -199,9 +198,7 @@ class ContentSecurityPolicyHandler
|
|||||||
{
|
{
|
||||||
if (isset($directivesSet[$type])) {
|
if (isset($directivesSet[$type])) {
|
||||||
$directives = $directivesSet[$type];
|
$directives = $directivesSet[$type];
|
||||||
} elseif (isset($directivesSet['default-src'])) {
|
} elseif (null === $directives = $this->getDirectiveFallback($directivesSet, $type)) {
|
||||||
$directives = $directivesSet['default-src'];
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +222,16 @@ class ContentSecurityPolicyHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDirectiveFallback(array $directiveSet, $type)
|
||||||
|
{
|
||||||
|
if (\in_array($type, ['script-src-elem', 'style-src-elem'], true) || !isset($directiveSet['default-src'])) {
|
||||||
|
// Let the browser fallback on it's own
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $directiveSet['default-src'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the Content-Security-Policy headers (either X-Content-Security-Policy or Content-Security-Policy) from
|
* Retrieves the Content-Security-Policy headers (either X-Content-Security-Policy or Content-Security-Policy) from
|
||||||
* a response.
|
* a response.
|
||||||
|
@ -131,7 +131,14 @@ class ContentSecurityPolicyHandlerTest extends TestCase
|
|||||||
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
||||||
$this->createRequest(),
|
$this->createRequest(),
|
||||||
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'']),
|
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'']),
|
||||||
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src-elem \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src-elem \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
$nonce,
|
||||||
|
['csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce],
|
||||||
|
$this->createRequest(),
|
||||||
|
$this->createResponse(['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\'']),
|
||||||
|
['Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; script-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'self\' \'unsafe-inline\'; style-src-elem \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$nonce,
|
$nonce,
|
||||||
|
@ -690,7 +690,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
try {
|
try {
|
||||||
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
|
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: '.$e->getMessage(), $file), 0, $e);
|
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $file).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->validate($configuration, $file);
|
return $this->validate($configuration, $file);
|
||||||
|
@ -454,28 +454,19 @@ class Filesystem
|
|||||||
$startPath = str_replace('\\', '/', $startPath);
|
$startPath = str_replace('\\', '/', $startPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stripDriveLetter = function ($path) {
|
$splitDriveLetter = function ($path) {
|
||||||
if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
|
return (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0]))
|
||||||
return substr($path, 2);
|
? [substr($path, 2), strtoupper($path[0])]
|
||||||
}
|
: [$path, null];
|
||||||
|
|
||||||
return $path;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$endPath = $stripDriveLetter($endPath);
|
$splitPath = function ($path) {
|
||||||
$startPath = $stripDriveLetter($startPath);
|
|
||||||
|
|
||||||
// Split the paths into arrays
|
|
||||||
$startPathArr = explode('/', trim($startPath, '/'));
|
|
||||||
$endPathArr = explode('/', trim($endPath, '/'));
|
|
||||||
|
|
||||||
$normalizePathArray = function ($pathSegments) {
|
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
foreach ($pathSegments as $segment) {
|
foreach (explode('/', trim($path, '/')) as $segment) {
|
||||||
if ('..' === $segment) {
|
if ('..' === $segment) {
|
||||||
array_pop($result);
|
array_pop($result);
|
||||||
} elseif ('.' !== $segment) {
|
} elseif ('.' !== $segment && '' !== $segment) {
|
||||||
$result[] = $segment;
|
$result[] = $segment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,8 +474,16 @@ class Filesystem
|
|||||||
return $result;
|
return $result;
|
||||||
};
|
};
|
||||||
|
|
||||||
$startPathArr = $normalizePathArray($startPathArr);
|
list($endPath, $endDriveLetter) = $splitDriveLetter($endPath);
|
||||||
$endPathArr = $normalizePathArray($endPathArr);
|
list($startPath, $startDriveLetter) = $splitDriveLetter($startPath);
|
||||||
|
|
||||||
|
$startPathArr = $splitPath($startPath);
|
||||||
|
$endPathArr = $splitPath($endPath);
|
||||||
|
|
||||||
|
if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
|
||||||
|
// End path is on another drive, so no relative path exists
|
||||||
|
return $endDriveLetter.':/'.($endPathArr ? implode('/', $endPathArr).'/' : '');
|
||||||
|
}
|
||||||
|
|
||||||
// Find for which directory the common path stops
|
// Find for which directory the common path stops
|
||||||
$index = 0;
|
$index = 0;
|
||||||
|
@ -1107,10 +1107,14 @@ class FilesystemTest extends FilesystemTestCase
|
|||||||
['/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'],
|
['/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'],
|
||||||
['/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'],
|
['/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'],
|
||||||
['C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
['C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
||||||
|
['C:/aa/bb/cc', 'c:/aa/dd/..', 'bb/cc/'],
|
||||||
['c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'],
|
['c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'],
|
||||||
['C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'],
|
['C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'],
|
||||||
['C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
['C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'],
|
||||||
['C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'],
|
['C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'],
|
||||||
|
['D:/', 'C:/aa/../bb/cc', 'D:/'],
|
||||||
|
['D:/aa/bb', 'C:/aa', 'D:/aa/bb/'],
|
||||||
|
['D:/../../aa/../bb/cc', 'C:/aa/dd/..', 'D:/bb/cc/'],
|
||||||
];
|
];
|
||||||
|
|
||||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||||
|
@ -959,7 +959,7 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac
|
|||||||
*
|
*
|
||||||
* @return FormInterface The child form
|
* @return FormInterface The child form
|
||||||
*
|
*
|
||||||
* @throws \OutOfBoundsException if the named child does not exist
|
* @throws OutOfBoundsException if the named child does not exist
|
||||||
*/
|
*/
|
||||||
public function offsetGet($name)
|
public function offsetGet($name)
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
|||||||
*
|
*
|
||||||
* @return self
|
* @return self
|
||||||
*
|
*
|
||||||
* @throws \OutOfBoundsException if the named child does not exist
|
* @throws Exception\OutOfBoundsException if the named child does not exist
|
||||||
*/
|
*/
|
||||||
public function get($name);
|
public function get($name);
|
||||||
|
|
||||||
|
@ -294,16 +294,16 @@ class InflectorTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider singularizeProvider
|
* @dataProvider singularizeProvider
|
||||||
*/
|
*/
|
||||||
public function testSingularize($plural, $singular)
|
public function testSingularize($plural, $expectedSingular)
|
||||||
{
|
{
|
||||||
$single = Inflector::singularize($plural);
|
$singular = Inflector::singularize($plural);
|
||||||
if (\is_string($singular) && \is_array($single)) {
|
if (\is_string($expectedSingular) && \is_array($singular)) {
|
||||||
$this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single));
|
$this->fail("--- Expected\n`string`: ".$expectedSingular."\n+++ Actual\n`array`: ".implode(', ', $singular));
|
||||||
} elseif (\is_array($singular) && \is_string($single)) {
|
} elseif (\is_array($expectedSingular) && \is_string($singular)) {
|
||||||
$this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single);
|
$this->fail("--- Expected\n`array`: ".implode(', ', $expectedSingular)."\n+++ Actual\n`string`: ".$singular);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertEquals($singular, $single);
|
$this->assertEquals($expectedSingular, $singular);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +62,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
try {
|
try {
|
||||||
$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
$parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
|
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $path).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$collection = new RouteCollection();
|
$collection = new RouteCollection();
|
||||||
|
@ -42,7 +42,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
try {
|
try {
|
||||||
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
|
$messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s".', $resource), 0, $e);
|
throw new InvalidResourceException(sprintf('The file "%s" does not contain valid YAML', $resource).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $messages && !\is_array($messages)) {
|
if (null !== $messages && !\is_array($messages)) {
|
||||||
|
@ -80,6 +80,9 @@ class EmailValidator extends ConstraintValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$value = (string) $value;
|
$value = (string) $value;
|
||||||
|
if ('' === $value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (null !== $constraint->normalizer) {
|
if (null !== $constraint->normalizer) {
|
||||||
$value = ($constraint->normalizer)($value);
|
$value = ($constraint->normalizer)($value);
|
||||||
|
@ -114,7 +114,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
try {
|
try {
|
||||||
$classes = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
$classes = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT);
|
||||||
} catch (ParseException $e) {
|
} catch (ParseException $e) {
|
||||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
|
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML', $path).': '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty file
|
// empty file
|
||||||
|
@ -352,7 +352,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="91">
|
<trans-unit id="91">
|
||||||
<source>This value should be either negative or zero.</source>
|
<source>This value should be either negative or zero.</source>
|
||||||
<target>Ova vrednost bi trebala biti pozitivna ili nula.</target>
|
<target>Ova vrednost bi trebala biti negativna ili nula.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="92">
|
<trans-unit id="92">
|
||||||
<source>This value is not a valid timezone.</source>
|
<source>This value is not a valid timezone.</source>
|
||||||
|
@ -60,6 +60,13 @@ class EmailValidatorTest extends ConstraintValidatorTestCase
|
|||||||
$this->assertNoViolation();
|
$this->assertNoViolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testObjectEmptyStringIsValid()
|
||||||
|
{
|
||||||
|
$this->validator->validate(new EmptyEmailObject(), new Email());
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
public function testExpectsStringCompatibleType()
|
public function testExpectsStringCompatibleType()
|
||||||
{
|
{
|
||||||
$this->expectException('Symfony\Component\Validator\Exception\UnexpectedValueException');
|
$this->expectException('Symfony\Component\Validator\Exception\UnexpectedValueException');
|
||||||
@ -411,3 +418,11 @@ class EmailValidatorTest extends ConstraintValidatorTestCase
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmptyEmailObject
|
||||||
|
{
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -53,6 +53,11 @@ class Entity extends EntityParent implements EntityInterfaceB
|
|||||||
$this->internal = $internal;
|
$this->internal = $internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFirstName()
|
||||||
|
{
|
||||||
|
return $this->firstName;
|
||||||
|
}
|
||||||
|
|
||||||
public function getInternal()
|
public function getInternal()
|
||||||
{
|
{
|
||||||
return $this->internal.' from getter';
|
return $this->internal.' from getter';
|
||||||
@ -141,4 +146,9 @@ class Entity extends EntityParent implements EntityInterfaceB
|
|||||||
{
|
{
|
||||||
$this->childB = $childB;
|
$this->childB = $childB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getReference()
|
||||||
|
{
|
||||||
|
return $this->reference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
|
|
||||||
const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
|
const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
|
||||||
|
|
||||||
|
const LAZY_PROPERTY = 'Symfony\Component\Validator\Validator\LazyProperty';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var FakeMetadataFactory
|
* @var FakeMetadataFactory
|
||||||
*/
|
*/
|
||||||
@ -54,6 +56,7 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
|
$this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
|
||||||
$this->metadataFactory->addMetadata($this->metadata);
|
$this->metadataFactory->addMetadata($this->metadata);
|
||||||
$this->metadataFactory->addMetadata($this->referenceMetadata);
|
$this->metadataFactory->addMetadata($this->referenceMetadata);
|
||||||
|
$this->metadataFactory->addMetadata(new ClassMetadata(self::LAZY_PROPERTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown(): void
|
protected function tearDown(): void
|
||||||
@ -510,7 +513,10 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->validate($entity);
|
$this->validate($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testArrayReference()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testArrayReference($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['key' => new Reference()];
|
$entity->reference = ['key' => new Reference()];
|
||||||
@ -528,7 +534,7 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
$this->referenceMetadata->addConstraint(new Callback([
|
$this->referenceMetadata->addConstraint(new Callback([
|
||||||
'callback' => $callback,
|
'callback' => $callback,
|
||||||
'groups' => 'Group',
|
'groups' => 'Group',
|
||||||
@ -548,8 +554,10 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->assertNull($violations[0]->getCode());
|
$this->assertNull($violations[0]->getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/symfony/symfony/issues/6246
|
/**
|
||||||
public function testRecursiveArrayReference()
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testRecursiveArrayReference($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [2 => ['key' => new Reference()]];
|
$entity->reference = [2 => ['key' => new Reference()]];
|
||||||
@ -567,7 +575,7 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
$this->referenceMetadata->addConstraint(new Callback([
|
$this->referenceMetadata->addConstraint(new Callback([
|
||||||
'callback' => $callback,
|
'callback' => $callback,
|
||||||
'groups' => 'Group',
|
'groups' => 'Group',
|
||||||
@ -611,7 +619,10 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->assertCount(0, $violations);
|
$this->assertCount(0, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testArrayTraversalCannotBeDisabled()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testArrayTraversalCannotBeDisabled($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['key' => new Reference()];
|
$entity->reference = ['key' => new Reference()];
|
||||||
@ -620,7 +631,7 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid([
|
$this->metadata->$constraintMethod('reference', new Valid([
|
||||||
'traverse' => false,
|
'traverse' => false,
|
||||||
]));
|
]));
|
||||||
$this->referenceMetadata->addConstraint(new Callback($callback));
|
$this->referenceMetadata->addConstraint(new Callback($callback));
|
||||||
@ -631,7 +642,10 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->assertCount(1, $violations);
|
$this->assertCount(1, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRecursiveArrayTraversalCannotBeDisabled()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testRecursiveArrayTraversalCannotBeDisabled($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [2 => ['key' => new Reference()]];
|
$entity->reference = [2 => ['key' => new Reference()]];
|
||||||
@ -640,9 +654,10 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
$context->addViolation('Message %param%', ['%param%' => 'value']);
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid([
|
$this->metadata->$constraintMethod('reference', new Valid([
|
||||||
'traverse' => false,
|
'traverse' => false,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$this->referenceMetadata->addConstraint(new Callback($callback));
|
$this->referenceMetadata->addConstraint(new Callback($callback));
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
@ -651,12 +666,15 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->assertCount(1, $violations);
|
$this->assertCount(1, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIgnoreScalarsDuringArrayTraversal()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testIgnoreScalarsDuringArrayTraversal($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = ['string', 1234];
|
$entity->reference = ['string', 1234];
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
|
|
||||||
@ -664,12 +682,15 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
$this->assertCount(0, $violations);
|
$this->assertCount(0, $violations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIgnoreNullDuringArrayTraversal()
|
/**
|
||||||
|
* @dataProvider getConstraintMethods
|
||||||
|
*/
|
||||||
|
public function testIgnoreNullDuringArrayTraversal($constraintMethod)
|
||||||
{
|
{
|
||||||
$entity = new Entity();
|
$entity = new Entity();
|
||||||
$entity->reference = [null];
|
$entity->reference = [null];
|
||||||
|
|
||||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
$this->metadata->$constraintMethod('reference', new Valid());
|
||||||
|
|
||||||
$violations = $this->validate($entity);
|
$violations = $this->validate($entity);
|
||||||
|
|
||||||
@ -1218,6 +1239,14 @@ abstract class AbstractValidatorTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getConstraintMethods()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['addPropertyConstraint'],
|
||||||
|
['addGetterConstraint'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function getTestReplaceDefaultGroup()
|
public function getTestReplaceDefaultGroup()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
@ -634,6 +634,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
|
|||||||
// See validateClassNode()
|
// See validateClassNode()
|
||||||
$cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups;
|
$cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups;
|
||||||
|
|
||||||
|
if ($value instanceof LazyProperty) {
|
||||||
|
$value = $value->getPropertyValue();
|
||||||
|
}
|
||||||
|
|
||||||
if (\is_array($value)) {
|
if (\is_array($value)) {
|
||||||
// Arrays are always traversed, independent of the specified
|
// Arrays are always traversed, independent of the specified
|
||||||
// traversal strategy
|
// traversal strategy
|
||||||
|
@ -618,8 +618,14 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
||||||
|
$isItComment = $this->isCurrentLineComment();
|
||||||
|
|
||||||
while ($this->moveToNextLine()) {
|
while ($this->moveToNextLine()) {
|
||||||
|
if ($isItComment && !$isItUnindentedCollection) {
|
||||||
|
$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
|
||||||
|
$isItComment = $this->isCurrentLineComment();
|
||||||
|
}
|
||||||
|
|
||||||
$indent = $this->getCurrentLineIndentation();
|
$indent = $this->getCurrentLineIndentation();
|
||||||
|
|
||||||
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
|
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
|
||||||
|
@ -74,3 +74,17 @@ yaml: |
|
|||||||
'foo #': baz
|
'foo #': baz
|
||||||
php: |
|
php: |
|
||||||
['foo #' => 'baz']
|
['foo #' => 'baz']
|
||||||
|
---
|
||||||
|
test: Comment before first item in unindented collection
|
||||||
|
brief: >
|
||||||
|
Comment directly before unindented collection is allowed
|
||||||
|
yaml: |
|
||||||
|
collection1:
|
||||||
|
# comment
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
collection2:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
php: |
|
||||||
|
['collection1' => ['a', 'b'], 'collection2' => ['a', 'b']]
|
||||||
|
Reference in New Issue
Block a user