Skip to content

Commit 84ed1f0

Browse files
committed
Set check-specific error messages
1 parent b48a2dd commit 84ed1f0

File tree

3 files changed

+152
-44
lines changed

3 files changed

+152
-44
lines changed

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
2424
class NoSuspiciousCharacters extends Constraint
2525
{
26+
public const RESTRICTION_LEVEL_ERROR = '1ece07dc-dca2-45f1-ba47-8d7dc3a12774';
27+
public const INVISIBLE_ERROR = '6ed60e6c-179b-4e93-8a6c-667d85c6de5e';
28+
public const CHAR_LIMIT_ERROR = 'ae6e496e-b315-4fdf-bea5-657accac631d';
29+
public const MIXED_NUMBERS_ERROR = '9f01fc26-3bc4-44b1-a6b1-c08e2412053a';
30+
public const HIDDEN_OVERLAY_ERROR = '56380dc5-0476-4f04-bbaa-b68cd1c2d974';
31+
32+
protected const ERROR_NAMES = [
33+
self::RESTRICTION_LEVEL_ERROR => 'RESTRICTION_LEVEL_ERROR',
34+
self::INVISIBLE_ERROR => 'INVISIBLE_ERROR',
35+
self::CHAR_LIMIT_ERROR => 'CHAR_LIMIT_ERROR',
36+
self::MIXED_NUMBERS_ERROR => 'MIXED_NUMBERS_ERROR',
37+
self::HIDDEN_OVERLAY_ERROR => 'INVALID_CASE_ERROR',
38+
];
39+
2640
/**
2741
* Check that a string satisfies the requirements for the specified restriction level.
2842
* It defaults to {@see self::RESTRICTION_LEVEL_HIGH} when using ICU >= 58,
@@ -58,7 +72,12 @@ class NoSuspiciousCharacters extends Constraint
5872
public const RESTRICTION_LEVEL_MINIMAL = 1342177280;
5973
public const RESTRICTION_LEVEL_NONE = 1610612736;
6074

61-
public $message = 'This value is suspicious.';
75+
public string $restrictionLevelMessage = 'Restriction level check failed.';
76+
public string $invisibleMessage = 'Invisible check failed.';
77+
public string $charLimitMessage = 'Char limit check failed.';
78+
public string $mixedNumbersMessage = 'Mixed numbers check failed.';
79+
public string $hiddenOverlayMessage = 'Hidden overlay check failed.';
80+
6281
public int $checks = self::CHECK_RESTRICTION_LEVEL | self::CHECK_INVISIBLE | self::CHECK_CHAR_LIMIT | self::CHECK_MIXED_NUMBERS | self::CHECK_HIDDEN_OVERLAY;
6382
public ?int $restrictionLevel = null;
6483
public array $profileLocales = [];
@@ -70,7 +89,11 @@ class NoSuspiciousCharacters extends Constraint
7089
*/
7190
public function __construct(
7291
array $options = null,
73-
string $message = null,
92+
string $restrictionLevelMessage = null,
93+
string $invisibleMessage = null,
94+
string $charLimitMessage = null,
95+
string $mixedNumbersMessage = null,
96+
string $hiddenOverlayMessage = null,
7497
int $checks = null,
7598
int $restrictionLevel = null,
7699
array $profileLocales = null,
@@ -84,7 +107,11 @@ public function __construct(
84107

85108
parent::__construct($options, $groups, $payload);
86109

87-
$this->message ??= $message;
110+
$this->restrictionLevelMessage ??= $restrictionLevelMessage;
111+
$this->invisibleMessage ??= $invisibleMessage;
112+
$this->charLimitMessage ??= $charLimitMessage;
113+
$this->mixedNumbersMessage ??= $mixedNumbersMessage;
114+
$this->hiddenOverlayMessage ??= $hiddenOverlayMessage;
88115
$this->checks ??= $checks;
89116
$this->restrictionLevel ??= $restrictionLevel;
90117
$this->profileLocales ??= $profileLocales;

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

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@
2222
*/
2323
class NoSuspiciousCharactersValidator extends ConstraintValidator implements LocaleAwareInterface
2424
{
25+
private const CHECK_ERROR = [
26+
NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL => [
27+
'code' => NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
28+
'messageProperty' => 'restrictionLevelMessage',
29+
],
30+
NoSuspiciousCharacters::CHECK_INVISIBLE => [
31+
'code' => NoSuspiciousCharacters::INVISIBLE_ERROR,
32+
'messageProperty' => 'invisibleMessage',
33+
],
34+
NoSuspiciousCharacters::CHECK_CHAR_LIMIT => [
35+
'code' => NoSuspiciousCharacters::CHAR_LIMIT_ERROR,
36+
'messageProperty' => 'charLimitMessage',
37+
],
38+
NoSuspiciousCharacters::CHECK_MIXED_NUMBERS => [
39+
'code' => NoSuspiciousCharacters::MIXED_NUMBERS_ERROR,
40+
'messageProperty' => 'mixedNumbersMessage',
41+
],
42+
NoSuspiciousCharacters::CHECK_HIDDEN_OVERLAY => [
43+
'code' => NoSuspiciousCharacters::HIDDEN_OVERLAY_ERROR,
44+
'messageProperty' => 'hiddenOverlayMessage',
45+
],
46+
];
47+
2548
private string $locale;
2649

2750
public function validate(mixed $value, Constraint $constraint)
@@ -55,16 +78,23 @@ public function validate(mixed $value, Constraint $constraint)
5578
}
5679
$checker->setAllowedLocales(implode(',', $allowedLocales));
5780

58-
$checker->setChecks($constraint->checks);
81+
foreach (self::CHECK_ERROR as $check => $error) {
82+
if (!($constraint->checks & $check)) {
83+
continue;
84+
}
5985

60-
if (!$checker->isSuspicious($value)) {
61-
return;
62-
}
86+
$checker->setChecks($check);
6387

64-
$this->context->buildViolation($constraint->message)
65-
->setParameter('{{ value }}', $this->formatValue($value))
66-
->addViolation()
67-
;
88+
if (!$checker->isSuspicious($value)) {
89+
continue;
90+
}
91+
92+
$this->context->buildViolation($constraint->{$error['messageProperty']})
93+
->setParameter('{{ value }}', $this->formatValue($value))
94+
->setCode($error['code'])
95+
->addViolation()
96+
;
97+
}
6898
}
6999

70100
public function setLocale(string $locale)

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

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,49 +40,100 @@ public function testNonSuspiciousStrings()
4040
/**
4141
* @dataProvider provideSuspiciousStrings
4242
*/
43-
public function testSuspiciousStrings(string $string, array $options)
43+
public function testSuspiciousStrings(string $string, array $options, string $errorCode, string $errorMessage)
4444
{
45-
$this->validator->validate($string, new NoSuspiciousCharacters(['message' => 'myMessage'] + $options));
45+
$this->validator->validate($string, new NoSuspiciousCharacters($options));
4646

47-
$this->buildViolation('myMessage')
47+
$this->buildViolation($errorMessage)
48+
->setCode($errorCode)
4849
->setParameter('{{ value }}', '"'.$string.'"')
4950
->assertRaised();
5051
}
5152

5253
public static function provideSuspiciousStrings(): iterable
5354
{
54-
yield 'Fails restriction level check because of character outside ASCII range' => ['à',
55+
yield 'Fails restriction level check because of character outside ASCII range' => [
56+
'à',
5557
['restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_ASCII],
58+
NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
59+
'Restriction level check failed.',
60+
];
61+
62+
yield 'Fails restriction level check because of mixed-script string' => [
63+
'àㄚ',
64+
[
65+
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT,
66+
'profileLocales' => ['zh_Hant_TW'],
67+
],
68+
NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
69+
'Restriction level check failed.',
70+
];
71+
72+
yield 'Fails restriction level check because of disallowed Armenian script' => [
73+
'àԱ',
74+
[
75+
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_HIGH,
76+
'profileLocales' => ['hy_AM'],
77+
],
78+
NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
79+
'Restriction level check failed.',
80+
];
81+
82+
yield 'Fails restriction level check because of disallowed Greek script' => [
83+
'àπ',
84+
[
85+
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE,
86+
'profileLocales' => ['el_GR'],
87+
],
88+
NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
89+
'Restriction level check failed.',
90+
];
91+
92+
yield 'Fails restriction level check because of Greek script absent from profile' => [
93+
'àπ',
94+
[
95+
'checks' => NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL,
96+
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_MINIMAL,
97+
],
98+
NoSuspiciousCharacters::RESTRICTION_LEVEL_ERROR,
99+
'Restriction level check failed.',
100+
];
101+
102+
yield 'Fails INVISIBLE check because of duplicated non-spacing mark' => [
103+
'à̀',
104+
[
105+
'checks' => NoSuspiciousCharacters::CHECK_INVISIBLE,
106+
],
107+
NoSuspiciousCharacters::INVISIBLE_ERROR,
108+
'Invisible check failed.',
109+
];
110+
111+
yield 'Fails CHAR_LIMIT check because of Greek script absent from profile' => [
112+
'àπ',
113+
[
114+
'checks' => NoSuspiciousCharacters::CHECK_CHAR_LIMIT,
115+
],
116+
NoSuspiciousCharacters::CHAR_LIMIT_ERROR,
117+
'Char limit check failed.',
118+
];
119+
120+
yield 'Fails MIXED_NUMBERS check because of different numbering systems' => [
121+
'8৪',
122+
[
123+
'checks' => NoSuspiciousCharacters::CHECK_MIXED_NUMBERS,
124+
],
125+
NoSuspiciousCharacters::MIXED_NUMBERS_ERROR,
126+
'Mixed numbers check failed.',
127+
];
128+
129+
yield 'Fails HIDDEN_OVERLAY check because of hidden combining character' => [
130+
'',
131+
[
132+
'checks' => NoSuspiciousCharacters::CHECK_HIDDEN_OVERLAY,
133+
],
134+
NoSuspiciousCharacters::HIDDEN_OVERLAY_ERROR,
135+
'Hidden overlay check failed.',
56136
];
57-
yield 'Fails restriction level check because of mixed-script string' => ['àㄚ', [
58-
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT,
59-
'profileLocales' => ['zh_Hant_TW'],
60-
]];
61-
yield 'Fails restriction level check because of disallowed Armenian script' => ['àԱ', [
62-
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_HIGH,
63-
'profileLocales' => ['hy_AM'],
64-
]];
65-
yield 'Fails restriction level check because of disallowed Greek script' => ['àπ', [
66-
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE,
67-
'profileLocales' => ['el_GR'],
68-
]];
69-
yield 'Fails restriction level check because of Greek script absent from profile' => ['àπ', [
70-
'checks' => NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL,
71-
'restrictionLevel' => NoSuspiciousCharacters::RESTRICTION_LEVEL_MINIMAL,
72-
]];
73-
74-
yield 'Fails INVISIBLE check because of duplicated non-spacing mark' => ['à̀', [
75-
'checks' => NoSuspiciousCharacters::CHECK_INVISIBLE,
76-
]];
77-
yield 'Fails CHAR_LIMIT check because of Greek script absent from profile' => ['àπ', [
78-
'checks' => NoSuspiciousCharacters::CHECK_CHAR_LIMIT,
79-
]];
80-
yield 'Fails MIXED_NUMBERS check because of different numbering systems' => ['8৪', [
81-
'checks' => NoSuspiciousCharacters::CHECK_MIXED_NUMBERS,
82-
]];
83-
yield 'Fails HIDDEN_OVERLAY check because of hidden combining character' => ['', [
84-
'checks' => NoSuspiciousCharacters::CHECK_HIDDEN_OVERLAY,
85-
]];
86137
}
87138

88139
public function testConstants()

0 commit comments

Comments
 (0)