diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 4e64932a49521..61dece394466b 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -3,7 +3,7 @@ CHANGELOG 7.2 --- - + * Add the `Yaml`, `Xml` and `Jwt` constraints * Make `PasswordStrengthValidator::estimateStrength()` public 7.1 diff --git a/src/Symfony/Component/Validator/Constraints/AbstractFormat.php b/src/Symfony/Component/Validator/Constraints/AbstractFormat.php new file mode 100644 index 0000000000000..affe6483c0630 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/AbstractFormat.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * Used for the format of values. + * + * @author Mokhtar Tlili + */ +abstract class AbstractFormat extends Constraint +{ + public string $format; + public string $message = 'This value should be valid {{ format }}.'; + + public function __construct(?string $message = null, ?array $options = null, ?array $groups = null, mixed $payload = null) + { + parent::__construct($options, $groups, $payload); + + $this->message = $message ?? $this->message; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/AbstractFormatValidator.php b/src/Symfony/Component/Validator/Constraints/AbstractFormatValidator.php new file mode 100644 index 0000000000000..d4f4cafc009d6 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/AbstractFormatValidator.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; + +/** + * Provides a base class for the validation of value format. + * + * @author Mokhtar Tlili + */ +abstract class AbstractFormatValidator extends ConstraintValidator +{ + public function validate(mixed $value, Constraint $constraint): void + { + if (!$constraint instanceof AbstractFormat) { + throw new UnexpectedTypeException($constraint, AbstractFormat::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!\is_scalar($value) && !$value instanceof \Stringable) { + throw new UnexpectedValueException($value, 'string'); + } + + if ($this->validateFormat((string) $value)) { + return; + } + + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ format }}', $constraint->format) + ->setCode($this->getErrorCode()) + ->addViolation(); + } + + /** + * Validate format value + */ + abstract protected function validateFormat(string $value): bool; + + abstract protected function getErrorCode(): string; +} diff --git a/src/Symfony/Component/Validator/Constraints/Json.php b/src/Symfony/Component/Validator/Constraints/Json.php index 3b85a347c5c64..bf19e84e2eda7 100644 --- a/src/Symfony/Component/Validator/Constraints/Json.php +++ b/src/Symfony/Component/Validator/Constraints/Json.php @@ -11,15 +11,13 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; - /** * Validates that a value has valid JSON syntax. * * @author Imad ZAIRIG */ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] -class Json extends Constraint +class Json extends AbstractFormat { public const INVALID_JSON_ERROR = '0789c8ad-2d2b-49a4-8356-e2ce63998504'; @@ -27,7 +25,7 @@ class Json extends Constraint self::INVALID_JSON_ERROR => 'INVALID_JSON_ERROR', ]; - public string $message = 'This value should be valid JSON.'; + public string $format = 'JSON'; /** * @param array|null $options @@ -35,8 +33,6 @@ class Json extends Constraint */ public function __construct(?array $options = null, ?string $message = null, ?array $groups = null, mixed $payload = null) { - parent::__construct($options, $groups, $payload); - - $this->message = $message ?? $this->message; + parent::__construct($message, $options, $groups, $payload); } } diff --git a/src/Symfony/Component/Validator/Constraints/JsonValidator.php b/src/Symfony/Component/Validator/Constraints/JsonValidator.php index e65831ca83be8..34a598ab2f0af 100644 --- a/src/Symfony/Component/Validator/Constraints/JsonValidator.php +++ b/src/Symfony/Component/Validator/Constraints/JsonValidator.php @@ -11,37 +11,18 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Exception\UnexpectedTypeException; -use Symfony\Component\Validator\Exception\UnexpectedValueException; - /** * @author Imad ZAIRIG */ -class JsonValidator extends ConstraintValidator +class JsonValidator extends AbstractFormatValidator { - public function validate(mixed $value, Constraint $constraint): void + protected function validateFormat(string $value): bool { - if (!$constraint instanceof Json) { - throw new UnexpectedTypeException($constraint, Json::class); - } - - if (null === $value || '' === $value) { - return; - } - - if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException($value, 'string'); - } - - $value = (string) $value; + return json_validate($value); + } - if (!json_validate($value)) { - $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) - ->setCode(Json::INVALID_JSON_ERROR) - ->addViolation(); - } + protected function getErrorCode(): string + { + return Json::INVALID_JSON_ERROR; } } diff --git a/src/Symfony/Component/Validator/Constraints/Jwt.php b/src/Symfony/Component/Validator/Constraints/Jwt.php new file mode 100644 index 0000000000000..8476fcd6237b5 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Jwt.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * Validates that a value is a valid jwt format. + * + * @author Mokhtar Tlili + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Jwt extends AbstractFormat +{ + public const INVALID_JWT_ERROR = '8f14e45f-e6e5-4c6c-9c17-68f22a1f3dff'; + + protected const ERROR_NAMES = [ + self::INVALID_JWT_ERROR => 'INVALID_JWT_ERROR', + ]; + + public string $format = 'JWT'; +} diff --git a/src/Symfony/Component/Validator/Constraints/JwtValidator.php b/src/Symfony/Component/Validator/Constraints/JwtValidator.php new file mode 100644 index 0000000000000..2c02038451089 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/JwtValidator.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @author Mokhtar Tlili + */ +class JwtValidator extends AbstractFormatValidator +{ + protected function validateFormat(string $value): bool + { + // Split the JWT into its three parts + $parts = explode('.', $value); + + // JWT should have exactly three parts + if (count($parts) !== 3) { + return false; + } + + [$header, $payload, $signature] = $parts; + + // Replace URL-safe characters with standard Base64 characters and decode + $decodedHeader = base64_decode(strtr($header, '-_', '+/')); + $decodedPayload = base64_decode(strtr($payload, '-_', '+/')); + + // Check if the decoded header and payload are valid JSON + if (!json_validate($decodedHeader) || !json_validate($decodedPayload)) { + return false; + } + + // At this point, it looks like a JWT + return true; + } + + protected function getErrorCode(): string + { + return Jwt::INVALID_JWT_ERROR; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Xml.php b/src/Symfony/Component/Validator/Constraints/Xml.php new file mode 100644 index 0000000000000..39f9f750e52b1 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Xml.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * Validates that a value is a valid xml format. + * + * @author Mokhtar Tlili + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Xml extends AbstractFormat +{ + public const INVALID_XML_ERROR = '0355230a-97b8-49da-b8cd-985bf3345bcf'; + + protected const ERROR_NAMES = [ + self::INVALID_XML_ERROR => 'INVALID_XML_ERROR', + ]; + + public string $format = 'XML'; +} diff --git a/src/Symfony/Component/Validator/Constraints/XmlValidator.php b/src/Symfony/Component/Validator/Constraints/XmlValidator.php new file mode 100644 index 0000000000000..620129e02878f --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/XmlValidator.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @author Mokhtar Tlili + */ +class XmlValidator extends AbstractFormatValidator +{ + protected function validateFormat(string $value): bool + { + return false !== @simplexml_load_string($value); + } + + protected function getErrorCode(): string + { + return Xml::INVALID_XML_ERROR; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Yaml.php b/src/Symfony/Component/Validator/Constraints/Yaml.php new file mode 100644 index 0000000000000..2f8807a944e8b --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Yaml.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Exception\LogicException; +use Symfony\Component\Yaml\Yaml as SymfonyYaml; + +/** + * Validates that a value is a valid yaml format. + * + * @author Mokhtar Tlili + */ +#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Yaml extends AbstractFormat +{ + public const INVALID_YAML_ERROR = '8f14e45f-e6e5-4c6c-9c17-68f22a1f3dff'; + + protected const ERROR_NAMES = [ + self::INVALID_YAML_ERROR => 'INVALID_YAML_ERROR', + ]; + + public string $format = 'YAML'; + + /** + * @param string[]|null $groups + * @param array $options + */ + public function __construct(?array $options = null, ?string $message = null, ?array $groups = null, mixed $payload = null) + { + if (!class_exists(SymfonyYaml::class)) { + throw new LogicException('The Yaml component is required to use the Yaml constraint. Try running "composer require symfony/yaml".'); + } + + parent::__construct($message, $options, $groups, $payload); + } +} diff --git a/src/Symfony/Component/Validator/Constraints/YamlValidator.php b/src/Symfony/Component/Validator/Constraints/YamlValidator.php new file mode 100644 index 0000000000000..5afad13801c47 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/YamlValidator.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml as SymfonyYaml; + +/** + * @author Mokhtar Tlili + */ +class YamlValidator extends AbstractFormatValidator +{ + protected function validateFormat(string $value): bool + { + try { + SymfonyYaml::parse($value); + return true; + } catch (ParseException) { + return false; + } + } + + protected function getErrorCode(): string + { + return Yaml::INVALID_YAML_ERROR; + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/JsonTest.php b/src/Symfony/Component/Validator/Tests/Constraints/JsonTest.php index 17208425f3881..3ebb33ca84391 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/JsonTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/JsonTest.php @@ -18,7 +18,7 @@ class JsonTest extends TestCase { - public function testAttributes() + public function testAttributes(): void { $metadata = new ClassMetadata(JsonDummy::class); $loader = new AttributeLoader(); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php index 92d8a20a79e28..87239fcab3de1 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php @@ -25,7 +25,7 @@ protected function createValidator(): JsonValidator /** * @dataProvider getValidValues */ - public function testJsonIsValid($value) + public function testJsonIsValid($value): void { $this->validator->validate($value, new Json()); @@ -35,7 +35,7 @@ public function testJsonIsValid($value) /** * @dataProvider getInvalidValues */ - public function testInvalidValues($value) + public function testInvalidValues($value): void { $constraint = new Json([ 'message' => 'myMessageTest', @@ -45,11 +45,12 @@ public function testInvalidValues($value) $this->buildViolation('myMessageTest') ->setParameter('{{ value }}', '"'.$value.'"') + ->setParameter('{{ format }}', $constraint->format) ->setCode(Json::INVALID_JSON_ERROR) ->assertRaised(); } - public static function getValidValues() + public static function getValidValues(): array { return [ ['{"planet":"earth", "country": "Morocco","city": "Rabat" ,"postcode" : 10160, "is_great": true, @@ -65,7 +66,7 @@ public static function getValidValues() ]; } - public static function getInvalidValues() + public static function getInvalidValues(): array { return [ ['{"foo": 3 "bar": 4}'], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/JwtTest.php b/src/Symfony/Component/Validator/Tests/Constraints/JwtTest.php new file mode 100644 index 0000000000000..7009867146f40 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/JwtTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Jwt; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; + +class JwtTest extends TestCase +{ + public function testAttributes(): void + { + $metadata = new ClassMetadata(JwtDummy::class); + $loader = new AttributeLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + [$bConstraint] = $metadata->properties['b']->getConstraints(); + self::assertSame('myMessage', $bConstraint->message); + self::assertSame(['Default', 'JwtDummy'], $bConstraint->groups); + + [$cConstraint] = $metadata->properties['c']->getConstraints(); + self::assertSame(['my_group'], $cConstraint->groups); + self::assertSame('some attached data', $cConstraint->payload); + } +} + +class JwtDummy +{ + #[Jwt] + private $a; + + #[Jwt(message: 'myMessage')] + private $b; + + #[Jwt(groups: ['my_group'], payload: 'some attached data')] + private $c; +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/JwtValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/JwtValidatorTest.php new file mode 100644 index 0000000000000..3685a95f8bbb4 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/JwtValidatorTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Jwt; +use Symfony\Component\Validator\Constraints\JwtValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +final class JwtValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): JwtValidator + { + return new JwtValidator(); + } + + public function testValidJwtValue(): void + { + $jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + $this->validator->validate($jwt, new Jwt()); + $this->assertNoViolation(); + } + + /** + * @dataProvider getInvalidJwtValues + */ + public function testInvalidJwtValue($value): void + { + $constraint = new Jwt(message: 'myMessage'); + $this->validator->validate($value, $constraint); + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$value.'"') + ->setParameter('{{ format }}', $constraint->format) + ->setCode(Jwt::INVALID_JWT_ERROR) + ->assertRaised(); + } + + public function getInvalidJwtValues(): array + { + // Incorrect JSON in header + $invalidHeader = base64_encode('{"alg": "HS256", "typ": "JWT""'); + $payload = base64_encode('{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}'); + $signature = 'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; + $jwt = "$invalidHeader.$payload.$signature"; + + return [ + ["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9-eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ-SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"], // invalid format + ["invalidheader.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"], // invalid header format + ["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.invalidpayload.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"], // invalid payload format + [$jwt], + ]; + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/XmlTest.php b/src/Symfony/Component/Validator/Tests/Constraints/XmlTest.php new file mode 100644 index 0000000000000..0389c9194a46e --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/XmlTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Xml; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; + +class XmlTest extends TestCase +{ + public function testAttributes(): void + { + $metadata = new ClassMetadata(XmlDummy::class); + $loader = new AttributeLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + [$bConstraint] = $metadata->properties['b']->getConstraints(); + self::assertSame('myMessage', $bConstraint->message); + self::assertSame(['Default', 'XmlDummy'], $bConstraint->groups); + + [$cConstraint] = $metadata->properties['c']->getConstraints(); + self::assertSame(['my_group'], $cConstraint->groups); + self::assertSame('some attached data', $cConstraint->payload); + } +} + +class XmlDummy +{ + #[Xml] + private $a; + + #[Xml(message: 'myMessage')] + private $b; + + #[Xml(groups: ['my_group'], payload: 'some attached data')] + private $c; +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/XmlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/XmlValidatorTest.php new file mode 100644 index 0000000000000..02336950a211e --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/XmlValidatorTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Xml; +use Symfony\Component\Validator\Constraints\XmlValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +use Symfony\Component\Validator\Tests\Constraints\Fixtures\StringableValue; + +final class XmlValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): XmlValidator + { + return new XmlValidator(); + } + + /** + * @dataProvider getValidXmlValues + */ + public function testValidXmlValue($value): void + { + $this->validator->validate($value, new Xml()); + $this->assertNoViolation(); + } + + /** + * @dataProvider getInvalidXmlValues + */ + public function testInValidXmlValue($value): void + { + $constraint = new Xml(message: 'myMessage'); + $this->validator->validate($value, $constraint); + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$value.'"') + ->setParameter('{{ format }}', $constraint->format) + ->setCode(Xml::INVALID_XML_ERROR) + ->assertRaised(); + } + + public static function getValidXmlValues(): array + { + $xml = << + + + + + + + + + + +XML; + return [ + [''], + [''], + [''], + [$xml], + [new StringableValue('test')], + ]; + } + + public static function getInvalidXmlValues(): array + { + return [ + ['test'], + [''], + [''], + [''], + [''], + [''], + [''], + ]; + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/YamlTest.php b/src/Symfony/Component/Validator/Tests/Constraints/YamlTest.php new file mode 100644 index 0000000000000..2c5ae10f82ae2 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/YamlTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Yaml; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; + +class YamlTest extends TestCase +{ + public function testAttributes(): void + { + $metadata = new ClassMetadata(YamlDummy::class); + $loader = new AttributeLoader(); + self::assertTrue($loader->loadClassMetadata($metadata)); + + [$bConstraint] = $metadata->properties['b']->getConstraints(); + self::assertSame('myMessage', $bConstraint->message); + self::assertSame(['Default', 'YamlDummy'], $bConstraint->groups); + + [$cConstraint] = $metadata->properties['c']->getConstraints(); + self::assertSame(['my_group'], $cConstraint->groups); + self::assertSame('some attached data', $cConstraint->payload); + } +} + +class YamlDummy +{ + #[Yaml] + private $a; + + #[Yaml(message: 'myMessage')] + private $b; + + #[Yaml(groups: ['my_group'], payload: 'some attached data')] + private $c; +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/YamlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/YamlValidatorTest.php new file mode 100644 index 0000000000000..0e4b1cbaa3cc7 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/YamlValidatorTest.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Yaml; +use Symfony\Component\Validator\Constraints\YamlValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +use Symfony\Component\Validator\Tests\Constraints\Fixtures\StringableValue; + +final class YamlValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): YamlValidator + { + return new YamlValidator(); + } + + /** + * @dataProvider getValidYamlValues + */ + public function testValidYamlValue($value): void + { + $this->validator->validate($value, new Yaml()); + $this->assertNoViolation(); + } + + /** + * @dataProvider getInvalidYamlValues + */ + public function testInvalidYamlValue($value): void + { + $constraint = new Yaml(message: 'myMessage'); + $this->validator->validate($value, $constraint); + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', '"'.$value.'"') + ->setParameter('{{ format }}', strtoupper($constraint->format)) + ->setCode(Yaml::INVALID_YAML_ERROR) + ->assertRaised(); + } + + public static function getValidYamlValues(): array + { + $yaml1 = <<