Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 34cebec

Browse filesBrowse files
committed
feature #45072 [Validator] Allow creating constraints with required arguments (norkunas)
This PR was merged into the 6.1 branch. Discussion ---------- [Validator] Allow creating constraints with required arguments | Q | A | ------------- | --- | Branch? | 6.1 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | N/A | License | MIT | Doc PR | symfony/symfony-docs#... Before PHP8 validation constraint usage was only possible with providing options as an array, but now with native PHP attributes we can provide as named arguments. And to require some arguments overriding `getRequiredOptions` method in Constraint was necessary to get proper validation. But since PHP8.1 we can just make arguments required in the Attribute constructor and try to unpack them because it is possible now. Commits ------- f22433f [Validator] Allow creating constraints with required arguments
2 parents 2634d8c + f22433f commit 34cebec
Copy full SHA for 34cebec

File tree

Expand file treeCollapse file tree

9 files changed

+116
-0
lines changed
Filter options
Expand file treeCollapse file tree

9 files changed

+116
-0
lines changed
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Validator\Attribute;
13+
14+
#[\Attribute(\Attribute::TARGET_METHOD)]
15+
final class HasNamedArguments
16+
{
17+
}

‎src/Symfony/Component/Validator/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Deprecate `Constraint::$errorNames`, use `Constraint::ERROR_NAMES` instead
88
* Deprecate constraint `ExpressionLanguageSyntax`, use `ExpressionSyntax` instead
99
* Add method `__toString()` to `ConstraintViolationInterface` & `ConstraintViolationListInterface`
10+
* Allow creating constraints with required arguments
1011

1112
6.0
1213
---

‎src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Mapping/Loader/AbstractLoader.php
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Validator\Mapping\Loader;
1313

14+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
1415
use Symfony\Component\Validator\Constraint;
1516
use Symfony\Component\Validator\Exception\MappingException;
1617

@@ -34,6 +35,11 @@ abstract class AbstractLoader implements LoaderInterface
3435

3536
protected $namespaces = [];
3637

38+
/**
39+
* @var array<class-string, bool>
40+
*/
41+
private array $namedArgumentsCache = [];
42+
3743
/**
3844
* Adds a namespace alias.
3945
*
@@ -78,6 +84,10 @@ protected function newConstraint(string $name, mixed $options = null): Constrain
7884
$className = self::DEFAULT_NAMESPACE.$name;
7985
}
8086

87+
if ($this->namedArgumentsCache[$className] ??= (bool) (new \ReflectionMethod($className, '__construct'))->getAttributes(HasNamedArguments::class)) {
88+
return new $className(...$options);
89+
}
90+
8191
return new $className($options);
8292
}
8393
}
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Validator\Tests\Fixtures;
13+
14+
use Symfony\Component\Validator\Attribute\HasNamedArguments;
15+
use Symfony\Component\Validator\Constraint;
16+
17+
#[\Attribute]
18+
final class ConstraintWithRequiredArgument extends Constraint
19+
{
20+
public string $requiredArg;
21+
22+
#[HasNamedArguments]
23+
public function __construct(string $requiredArg, array $groups = null, mixed $payload = null)
24+
{
25+
parent::__construct([], $groups, $payload);
26+
27+
$this->requiredArg = $requiredArg;
28+
}
29+
}
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\Validator\Tests\Fixtures;
4+
5+
class Entity_81
6+
{
7+
public $title;
8+
}

‎src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
use Symfony\Component\Validator\Tests\Fixtures\Annotation\GroupSequenceProviderEntity;
2929
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
3030
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
31+
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithRequiredArgument;
32+
use Symfony\Component\Validator\Tests\Fixtures\Entity_81;
3133

3234
class XmlFileLoaderTest extends TestCase
3335
{
@@ -98,6 +100,19 @@ public function testLoadClassMetadataWithNonStrings()
98100
$this->assertFalse($constraints[0]->match);
99101
}
100102

103+
public function testLoadClassMetadataWithRequiredArguments()
104+
{
105+
$loader = new XmlFileLoader(__DIR__.'/constraint-mapping-required-arg.xml');
106+
$metadata = new ClassMetadata(Entity_81::class);
107+
108+
$loader->loadClassMetadata($metadata);
109+
110+
$expected = new ClassMetadata(Entity_81::class);
111+
$expected->addPropertyConstraint('title', new ConstraintWithRequiredArgument('X'));
112+
113+
$this->assertEquals($expected, $metadata);
114+
}
115+
101116
public function testLoadGroupSequenceProvider()
102117
{
103118
$loader = new XmlFileLoader(__DIR__.'/constraint-mapping.xml');

‎src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
use Symfony\Component\Validator\Tests\Fixtures\Annotation\GroupSequenceProviderEntity;
2626
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
2727
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
28+
use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithRequiredArgument;
29+
use Symfony\Component\Validator\Tests\Fixtures\Entity_81;
2830

2931
class YamlFileLoaderTest extends TestCase
3032
{
@@ -138,6 +140,19 @@ public function testLoadClassMetadataWithConstants()
138140
$this->assertEquals($expected, $metadata);
139141
}
140142

143+
public function testLoadClassMetadataWithRequiredArguments()
144+
{
145+
$loader = new YamlFileLoader(__DIR__.'/constraint-mapping-required-arg.yml');
146+
$metadata = new ClassMetadata(Entity_81::class);
147+
148+
$loader->loadClassMetadata($metadata);
149+
150+
$expected = new ClassMetadata(Entity_81::class);
151+
$expected->addPropertyConstraint('title', new ConstraintWithRequiredArgument('X'));
152+
153+
$this->assertEquals($expected, $metadata);
154+
}
155+
141156
public function testLoadGroupSequenceProvider()
142157
{
143158
$loader = new YamlFileLoader(__DIR__.'/constraint-mapping.yml');
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" ?>
2+
3+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
6+
7+
<class name="Symfony\Component\Validator\Tests\Fixtures\Entity_81">
8+
9+
<property name="title">
10+
<constraint name="Symfony\Component\Validator\Tests\Fixtures\ConstraintWithRequiredArgument">
11+
<option name="requiredArg">X</option>
12+
</constraint>
13+
</property>
14+
</class>
15+
16+
</constraint-mapping>
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Symfony\Component\Validator\Tests\Fixtures\Entity_81:
2+
properties:
3+
title:
4+
- Symfony\Component\Validator\Tests\Fixtures\ConstraintWithRequiredArgument:
5+
requiredArg: 'X'

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.