Skip to content

Commit 5e0025b

Browse files
Merge pull request #772 from systemli/fix/lowercase_violator
Add lowercase validator and use it for email and name trait
2 parents e9f8829 + da22942 commit 5e0025b

File tree

8 files changed

+140
-3
lines changed

8 files changed

+140
-3
lines changed

default_translations/de/validators.de.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
---
12
form:
23
weak_password: Das Passwort entspricht nicht den Sicherheitsanforderungen.
34
forbidden_char: Das Passwort enthält nicht erlaubte Zeichen.
45
different-password: Die Passwörter stimmen nicht überein.
56
invalid-email: Die E-Mail-Adresse ist ungültig.
67
wrong-password: Das eingegebene Passwort ist falsch
78
identical-passwords: Das neue Passwort stimmt mit dem aktuellen überein.
8-
missing-domain: Die Domain wird nicht vom System verwaltet und kann nicht benutzt
9-
werden.
9+
missing-domain: Die Domain wird nicht vom System verwaltet und kann nicht benutzt werden.
1010
registration-recovery-token-noack: Dieses Feld muss ausgewählt werden.
1111
invalid-token: Der Code hat ein ungültiges Format.
12+
twofactor-secret-invalid: "Der Verifizierungscode ist ungültig."
13+
twofactor-backup-ack-missing: "Dies muss muss ausgewählt werden."
14+
lowercase: "Die Zeichenkette darf keine Großbuchstaben enthalten."
1215

1316
registration:
1417
voucher-invalid: Der Einladungscode ist ungültig.

default_translations/en/validators.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ form:
1111
invalid-token: "This token has an invalid format."
1212
twofactor-secret-invalid: "The verification code is not valid."
1313
twofactor-backup-ack-missing: "This needs to be checked."
14+
lowercase: "The string must not contain uppercase letters."
1415

1516
registration:
1617
voucher-invalid: "The invite code is invalid."

src/Creator/DomainCreator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function create(string $name): Domain
1616
{
1717
$domain = DomainFactory::create($name);
1818

19-
$this->validate($domain, ['Default', 'unique']);
19+
$this->validate($domain, ['Default', 'lowercase', 'unique']);
2020
$this->save($domain);
2121

2222
$this->eventDispatcher->dispatch(new DomainCreatedEvent($domain), DomainCreatedEvent::NAME);

src/Traits/EmailTrait.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Traits;
44

5+
use App\Validator\Constraints\Lowercase;
56
use Doctrine\ORM\Mapping as ORM;
67
use Symfony\Component\Validator\Constraints as Assert;
78

@@ -10,6 +11,7 @@ trait EmailTrait
1011
{
1112
#[ORM\Column(unique: true)]
1213
#[Assert\NotNull]
14+
#[Lowercase]
1315
#[Assert\Email]
1416
private ?string $email = '';
1517

src/Traits/NameTrait.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Traits;
44

5+
use App\Validator\Constraints\Lowercase;
56
use Doctrine\ORM\Mapping as ORM;
67
use Symfony\Component\Validator\Constraints as Assert;
78

@@ -10,6 +11,7 @@ trait NameTrait
1011
#[ORM\Column(unique: true)]
1112
#[Assert\NotNull]
1213
#[Assert\NotBlank]
14+
#[Lowercase]
1315
private ?string $name = null;
1416

1517
public function getName(): ?string
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Validator\Constraints;
4+
5+
6+
use Symfony\Component\Validator\Constraint;
7+
8+
#[\Attribute]
9+
class Lowercase extends Constraint
10+
{
11+
public string $message = 'form.lowercase';
12+
public string $mode = 'strict';
13+
14+
public function __construct(?string $mode = null, ?string $message = null, ?array $groups = null, $payload = null) {
15+
parent::__construct([], $groups, $payload);
16+
17+
$this->mode = $mode ?? $this->mode;
18+
}
19+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Validator\Constraints;
4+
5+
use Symfony\Component\Validator\Constraint;
6+
use Symfony\Component\Validator\ConstraintValidator;
7+
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
8+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
9+
10+
class LowercaseValidator extends ConstraintValidator
11+
{
12+
public function validate(mixed $value, Constraint $constraint): void
13+
{
14+
if (!$constraint instanceof Lowercase) {
15+
throw new UnexpectedTypeException($constraint, Lowercase::class);
16+
}
17+
18+
// custom constraints should ignore null and empty values to allow
19+
// other constraints (NotBlank, NotNull, etc.) to take care of that
20+
if (null === $value || '' === $value) {
21+
return;
22+
}
23+
24+
if (!is_string($value)) {
25+
throw new UnexpectedValueException($value, 'string');
26+
}
27+
28+
if (!preg_match('/[A-Z]/', $value, $matches)) {
29+
return;
30+
}
31+
32+
$this->context->buildViolation($constraint->message)
33+
->setParameter('{{ string }}', $value)
34+
->addViolation();
35+
}
36+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace App\Tests\Validator\Constraints;
4+
5+
use App\Validator\Constraints\Lowercase;
6+
use App\Validator\Constraints\LowercaseValidator;
7+
use stdClass;
8+
use Symfony\Component\Validator\Constraints\Valid;
9+
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
10+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
11+
12+
class LowercaseValidatorTest extends ConstraintValidatorTestCase
13+
{
14+
private $domain = 'example.org';
15+
private $minLength = 3;
16+
private $maxLength = 10;
17+
18+
protected function createValidator(): LowercaseValidator
19+
{
20+
return new LowercaseValidator();
21+
}
22+
23+
public function testExpectsStringType(): void
24+
{
25+
$this->expectException(UnexpectedTypeException::class);
26+
$this->validator->validate('string', new Valid());
27+
}
28+
29+
public function testNullIsValid(): void
30+
{
31+
$this->validator->validate(null, new Lowercase());
32+
$this->assertNoViolation();
33+
}
34+
35+
public function testEmptyStringIsValid(): void
36+
{
37+
$this->validator->validate('', new Lowercase());
38+
$this->assertNoViolation();
39+
}
40+
41+
public function testExpectsStringCompatibleType(): void
42+
{
43+
$this->expectException(UnexpectedTypeException::class);
44+
$this->validator->validate(new stdClass(), new Lowercase());
45+
}
46+
47+
public function testValidateValid(): void
48+
{
49+
$this->validator->validate('example#3!%', new Lowercase());
50+
$this->validator->validate('example.org', new Lowercase());
51+
$this->validator->validate('[email protected]', new Lowercase());
52+
$this->assertNoViolation();
53+
}
54+
55+
/**
56+
* @dataProvider getStrings
57+
*/
58+
public function testValidateUppercaseInvalid(string $string): void
59+
{
60+
$this->validator->validate($string, new Lowercase());
61+
$this->buildViolation('form.lowercase')
62+
->setParameter('{{ string }}', $string)
63+
->assertRaised();
64+
}
65+
66+
public static function getStrings(): array
67+
{
68+
return [
69+
['Example#3!%'],
70+
['example.Org'],
71+
72+
];
73+
}
74+
}

0 commit comments

Comments
 (0)