Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
90.00% covered (success)
90.00%
54 / 60
88.76% covered (warning)
88.76%
79 / 89
32.99% covered (danger)
32.99%
32 / 97
68.75% covered (warning)
68.75%
11 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
Validator
90.00% covered (success)
90.00%
54 / 60
88.76% covered (warning)
88.76%
79 / 89
32.99% covered (danger)
32.99%
32 / 97
81.25% covered (warning)
81.25%
13 / 16
682.71
0.00% covered (danger)
0.00%
0 / 1
 getValidationErrors
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 notEmpty
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
13 / 13
11.11% covered (danger)
11.11%
4 / 36
100.00% covered (success)
100.00%
1 / 1
41.41
 validate
50.00% covered (danger)
50.00%
1 / 2
66.67% covered (warning)
66.67%
2 / 3
50.00% covered (danger)
50.00%
1 / 2
0.00% covered (danger)
0.00%
0 / 1
2.50
 requireNotNull
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 requireNotEmpty
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 requireValidEmail
100.00% covered (success)
100.00%
4 / 4
87.50% covered (warning)
87.50%
7 / 8
33.33% covered (danger)
33.33%
2 / 6
100.00% covered (success)
100.00%
1 / 1
5.67
 requireValidUrl
83.33% covered (warning)
83.33%
10 / 12
80.00% covered (warning)
80.00%
16 / 20
20.00% covered (danger)
20.00%
4 / 20
0.00% covered (danger)
0.00%
0 / 1
32.09
 requireMinLength
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
7 / 7
60.00% covered (warning)
60.00%
3 / 5
100.00% covered (success)
100.00%
1 / 1
5.02
 requireMaxLength
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
7 / 7
60.00% covered (warning)
60.00%
3 / 5
100.00% covered (success)
100.00%
1 / 1
5.02
 requireMin
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
5 / 5
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
4.12
 requireMinIfNotNull
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 requireMax
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
5 / 5
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
4.12
 requireMaxIfNotNull
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 requireValidUuidV4
100.00% covered (success)
100.00%
3 / 3
83.33% covered (warning)
83.33%
5 / 6
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
2.50
 require
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace App\Shared\Domain\Validation;
4
5use App\Shared\Domain\Exception\BaseErrorCode;
6use App\Shared\Domain\Exception\ErrorCode;
7use App\Shared\Domain\Exception\ValidationException;
8use App\Shared\Domain\Model\EntityId;
9
10/**
11 * @author Wilhelm Zwertvaegher
12 */
13
14/**
15 * @author Wilhelm Zwertvaegher
16 */
17
18class Validator
19{
20
21    public ValidationErrors $validationErrors;
22
23    /**
24     * @return ValidationErrors
25     */
26    public function getValidationErrors(): ValidationErrors
27    {
28        return $this->validationErrors;
29    }
30
31    /**
32     *
33     */
34    public function __construct()
35    {
36        $this->validationErrors = new ValidationErrors();
37    }
38
39    /**
40     * @param string $fieldName
41     * @param mixed $fieldValue
42     * @return bool
43     */
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
47            || $fieldValue === ''
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
49            || is_array($fieldValue) && count($fieldValue) === 0
50        ) {
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
53        }
54        return true;
55    }
56
57    /**
58     * @throws ValidationException
59     */
60    public function validate(): void
61    {
62        if ($this->validationErrors->hasErrors()) {
63            throw new ValidationException($this->validationErrors);
64        }
65    }
66
67    /**
68     * @param string $fieldName
69     * @param mixed $fieldValue
70     * @return $this
71     */
72    public function requireNotNull(string $fieldName, mixed $fieldValue): self
73    {
74        if (null === $fieldValue) {
75            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_NULL));
76        }
77        return $this;
78    }
79
80    /**
81     * @param string $fieldName
82     * @param mixed $fieldValue
83     * @return $this
84     */
85    public function requireNotEmpty(string $fieldName, mixed $fieldValue): self
86    {
87        $this->notEmpty($fieldName, $fieldValue);
88        return $this;
89    }
90
91    /**
92     * @param string $fieldName
93     * @param string $fieldValue
94     * @return $this
95     */
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
100            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_EMAIL, ['invalid' => sprintf('%s is not a valid email', $fieldValue)]));
101        }
102        return $this;
103    }
104
105    /**
106     * @param string $fieldName
107     * @param string $fieldValue
108     * @return $this
109     */
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
115                throw new \Exception('Malformed URL');
116            }
117
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
119                throw new \Exception('URL must start with http(s).');
120            }
121
122            if (empty($parts['host'])) {
123                throw new \Exception('URL must contain a host.');
124            }
125
126            if (!str_contains($parts['host'], '.')) {
127                throw new \Exception('URL must contain a valid host.');
128            }
129
130        } catch (\Exception $e) {
131            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_URL, ['invalid' => $e->getMessage()]));
132        }
133
134        return $this;
135    }
136
137    /**
138     * @param string $fieldName
139     * @param string $fieldValue
140     * @param int $minLength
141     * @return $this
142     */
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
146            throw new \InvalidArgumentException("minLength must be greater than 0");
147        }
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
149            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SHORT));
150        }
151        return $this;
152    }
153
154    /**
155     * @param string $fieldName
156     * @param string $fieldValue
157     * @param int $maxLength
158     * @return $this
159     */
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
163            throw new \InvalidArgumentException("maxLength must be greater than 0");
164        }
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
166            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_LONG));
167        }
168        return $this;
169    }
170
171    /**
172     * @param string $fieldName
173     * @param int $fieldValue
174     * @param int $minValue
175     * @return $this
176     */
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
180            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
181        }
182        return $this;
183    }
184
185    /**
186     * @param string $fieldName
187     * @param int $fieldValue
188     * @param int $minValue
189     * @return $this
190     */
191    public function requireMinIfNotNull(string $fieldName, int $fieldValue, int $minValue): self
192    {
193        if ($fieldValue < $minValue) {
194            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
195        }
196        return $this;
197    }
198
199    /**
200     * @param string $fieldName
201     * @param int $fieldValue
202     * @param int $maxValue
203     * @return $this
204     */
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
208            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
209        }
210        return $this;
211    }
212
213    /**
214     * @param string $fieldName
215     * @param int $fieldValue
216     * @param int $maxValue
217     * @return $this
218     */
219    public function requireMaxIfNotNull(string $fieldName, int $fieldValue, int $maxValue): self
220    {
221        if ($fieldValue > $maxValue) {
222            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
223        }
224        return $this;
225    }
226
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
230            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_UUID));
231        }
232
233        return $this;
234    }
235
236    /**
237     * @param string $fieldName
238     * @param callable():bool $supplier
239     * @param BaseErrorCode $errorCode
240     * @return $this
241     */
242    public function require(string $fieldName, callable $supplier, BaseErrorCode $errorCode): self
243    {
244        if (true !== $supplier()) {
245            $this->validationErrors->add(new ValidationError($fieldName, $errorCode));
246        }
247        return $this;
248    }
249}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

Validator->__construct
36        $this->validationErrors = new ValidationErrors();
37    }
Validator->getValidationErrors
28        return $this->validationErrors;
29    }
Validator->notEmpty
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
 
47            || $fieldValue === ''
 
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
 
49            || is_array($fieldValue) && count($fieldValue) === 0
 
54        return true;
55    }
Validator->require
242    public function require(string $fieldName, callable $supplier, BaseErrorCode $errorCode): self
243    {
244        if (true !== $supplier()) {
 
245            $this->validationErrors->add(new ValidationError($fieldName, $errorCode));
246        }
247        return $this;
 
247        return $this;
248    }
242    public function require(string $fieldName, callable $supplier, BaseErrorCode $errorCode): self
243    {
244        if (true !== $supplier()) {
 
247        return $this;
248    }
Validator->requireMax
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
208            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
209        }
210        return $this;
 
210        return $this;
211    }
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
210        return $this;
211    }
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
208            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
209        }
210        return $this;
 
210        return $this;
211    }
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
 
210        return $this;
211    }
Validator->requireMaxIfNotNull
219    public function requireMaxIfNotNull(string $fieldName, int $fieldValue, int $maxValue): self
220    {
221        if ($fieldValue > $maxValue) {
 
222            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
223        }
224        return $this;
 
224        return $this;
225    }
219    public function requireMaxIfNotNull(string $fieldName, int $fieldValue, int $maxValue): self
220    {
221        if ($fieldValue > $maxValue) {
 
224        return $this;
225    }
Validator->requireMaxLength
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
 
163            throw new \InvalidArgumentException("maxLength must be greater than 0");
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
166            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_LONG));
167        }
168        return $this;
 
168        return $this;
169    }
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
168        return $this;
169    }
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
166            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_LONG));
167        }
168        return $this;
 
168        return $this;
169    }
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
 
168        return $this;
169    }
Validator->requireMin
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
180            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
181        }
182        return $this;
 
182        return $this;
183    }
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
182        return $this;
183    }
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
180            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
181        }
182        return $this;
 
182        return $this;
183    }
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
 
182        return $this;
183    }
Validator->requireMinIfNotNull
191    public function requireMinIfNotNull(string $fieldName, int $fieldValue, int $minValue): self
192    {
193        if ($fieldValue < $minValue) {
 
194            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
195        }
196        return $this;
 
196        return $this;
197    }
191    public function requireMinIfNotNull(string $fieldName, int $fieldValue, int $minValue): self
192    {
193        if ($fieldValue < $minValue) {
 
196        return $this;
197    }
Validator->requireMinLength
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
 
146            throw new \InvalidArgumentException("minLength must be greater than 0");
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
149            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SHORT));
150        }
151        return $this;
 
151        return $this;
152    }
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
151        return $this;
152    }
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
149            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SHORT));
150        }
151        return $this;
 
151        return $this;
152    }
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
 
151        return $this;
152    }
Validator->requireNotEmpty
85    public function requireNotEmpty(string $fieldName, mixed $fieldValue): self
86    {
87        $this->notEmpty($fieldName, $fieldValue);
88        return $this;
89    }
Validator->requireNotNull
72    public function requireNotNull(string $fieldName, mixed $fieldValue): self
73    {
74        if (null === $fieldValue) {
 
75            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_NULL));
76        }
77        return $this;
 
77        return $this;
78    }
72    public function requireNotNull(string $fieldName, mixed $fieldValue): self
73    {
74        if (null === $fieldValue) {
 
77        return $this;
78    }
Validator->requireValidEmail
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
100            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_EMAIL, ['invalid' => sprintf('%s is not a valid email', $fieldValue)]));
101        }
102        return $this;
 
102        return $this;
103    }
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
102        return $this;
103    }
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
100            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_EMAIL, ['invalid' => sprintf('%s is not a valid email', $fieldValue)]));
101        }
102        return $this;
 
102        return $this;
103    }
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
102        return $this;
103    }
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
100            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_EMAIL, ['invalid' => sprintf('%s is not a valid email', $fieldValue)]));
101        }
102        return $this;
 
102        return $this;
103    }
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
 
102        return $this;
103    }
Validator->requireValidUrl
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
115                throw new \Exception('Malformed URL');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
119                throw new \Exception('URL must start with http(s).');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
123                throw new \Exception('URL must contain a host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
119                throw new \Exception('URL must start with http(s).');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
123                throw new \Exception('URL must contain a host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
119                throw new \Exception('URL must start with http(s).');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
123                throw new \Exception('URL must contain a host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
 
122            if (empty($parts['host'])) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
126            if (!str_contains($parts['host'], '.')) {
 
127                throw new \Exception('URL must contain a valid host.');
 
134        return $this;
135    }
130        } catch (\Exception $e) {
 
131            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_URL, ['invalid' => $e->getMessage()]));
132        }
133
134        return $this;
 
134        return $this;
135    }
Validator->requireValidUuidV4
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
230            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_UUID));
231        }
232
233        return $this;
 
233        return $this;
234    }
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
233        return $this;
234    }
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
230            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_UUID));
231        }
232
233        return $this;
 
233        return $this;
234    }
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
 
233        return $this;
234    }
Validator->validate
62        if ($this->validationErrors->hasErrors()) {
 
63            throw new ValidationException($this->validationErrors);
62        if ($this->validationErrors->hasErrors()) {
 
65    }
{main}
3namespace App\Shared\Domain\Validation;
4
5use App\Shared\Domain\Exception\BaseErrorCode;
6use App\Shared\Domain\Exception\ErrorCode;
7use App\Shared\Domain\Exception\ValidationException;
8use App\Shared\Domain\Model\EntityId;
9
10/**
11 * @author Wilhelm Zwertvaegher
12 */
13
14/**
15 * @author Wilhelm Zwertvaegher
16 */
17
18class Validator
19{
20
21    public ValidationErrors $validationErrors;
22
23    /**
24     * @return ValidationErrors
25     */
26    public function getValidationErrors(): ValidationErrors
27    {
28        return $this->validationErrors;
29    }
30
31    /**
32     *
33     */
34    public function __construct()
35    {
36        $this->validationErrors = new ValidationErrors();
37    }
38
39    /**
40     * @param string $fieldName
41     * @param mixed $fieldValue
42     * @return bool
43     */
44    private function notEmpty(string $fieldName, mixed $fieldValue): bool
45    {
46        if ($fieldValue === null
47            || $fieldValue === ''
48            || $fieldValue instanceof EntityId && $fieldValue->value() === '    '
49            || is_array($fieldValue) && count($fieldValue) === 0
50        ) {
51            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_EMPTY, ['empty' => 'Field cannot be empty']));
52            return false;
53        }
54        return true;
55    }
56
57    /**
58     * @throws ValidationException
59     */
60    public function validate(): void
61    {
62        if ($this->validationErrors->hasErrors()) {
63            throw new ValidationException($this->validationErrors);
64        }
65    }
66
67    /**
68     * @param string $fieldName
69     * @param mixed $fieldValue
70     * @return $this
71     */
72    public function requireNotNull(string $fieldName, mixed $fieldValue): self
73    {
74        if (null === $fieldValue) {
75            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_CANNOT_BE_NULL));
76        }
77        return $this;
78    }
79
80    /**
81     * @param string $fieldName
82     * @param mixed $fieldValue
83     * @return $this
84     */
85    public function requireNotEmpty(string $fieldName, mixed $fieldValue): self
86    {
87        $this->notEmpty($fieldName, $fieldValue);
88        return $this;
89    }
90
91    /**
92     * @param string $fieldName
93     * @param string $fieldValue
94     * @return $this
95     */
96    public function requireValidEmail(string $fieldName, string $fieldValue): self
97    {
98        $pattern = "/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$/";
99        if ($this->notEmpty($fieldName, $fieldValue) && !preg_match($pattern, $fieldValue)) {
100            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_EMAIL, ['invalid' => sprintf('%s is not a valid email', $fieldValue)]));
101        }
102        return $this;
103    }
104
105    /**
106     * @param string $fieldName
107     * @param string $fieldValue
108     * @return $this
109     */
110    public function requireValidUrl(string $fieldName, string $fieldValue): self
111    {
112        try {
113            $parts = parse_url($fieldValue);
114            if (!is_array($parts)) {
115                throw new \Exception('Malformed URL');
116            }
117
118            if (empty($parts['scheme']) || !str_starts_with($parts['scheme'], 'http')) {
119                throw new \Exception('URL must start with http(s).');
120            }
121
122            if (empty($parts['host'])) {
123                throw new \Exception('URL must contain a host.');
124            }
125
126            if (!str_contains($parts['host'], '.')) {
127                throw new \Exception('URL must contain a valid host.');
128            }
129
130        } catch (\Exception $e) {
131            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_URL, ['invalid' => $e->getMessage()]));
132        }
133
134        return $this;
135    }
136
137    /**
138     * @param string $fieldName
139     * @param string $fieldValue
140     * @param int $minLength
141     * @return $this
142     */
143    public function requireMinLength(string $fieldName, string $fieldValue, int $minLength): self
144    {
145        if ($minLength < 1) {
146            throw new \InvalidArgumentException("minLength must be greater than 0");
147        }
148        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) < $minLength) {
149            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SHORT));
150        }
151        return $this;
152    }
153
154    /**
155     * @param string $fieldName
156     * @param string $fieldValue
157     * @param int $maxLength
158     * @return $this
159     */
160    public function requireMaxLength(string $fieldName, string $fieldValue, int $maxLength): self
161    {
162        if ($maxLength < 1) {
163            throw new \InvalidArgumentException("maxLength must be greater than 0");
164        }
165        if ($this->notEmpty($fieldName, $fieldValue) && strlen($fieldValue) > $maxLength) {
166            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_LONG));
167        }
168        return $this;
169    }
170
171    /**
172     * @param string $fieldName
173     * @param int $fieldValue
174     * @param int $minValue
175     * @return $this
176     */
177    public function requireMin(string $fieldName, int $fieldValue, int $minValue): self
178    {
179        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue < $minValue) {
180            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
181        }
182        return $this;
183    }
184
185    /**
186     * @param string $fieldName
187     * @param int $fieldValue
188     * @param int $minValue
189     * @return $this
190     */
191    public function requireMinIfNotNull(string $fieldName, int $fieldValue, int $minValue): self
192    {
193        if ($fieldValue < $minValue) {
194            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_SMALL, ["min" => $minValue]));
195        }
196        return $this;
197    }
198
199    /**
200     * @param string $fieldName
201     * @param int $fieldValue
202     * @param int $maxValue
203     * @return $this
204     */
205    public function requireMax(string $fieldName, int $fieldValue, int $maxValue): self
206    {
207        if ($this->notEmpty($fieldName, $fieldValue) && $fieldValue > $maxValue) {
208            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
209        }
210        return $this;
211    }
212
213    /**
214     * @param string $fieldName
215     * @param int $fieldValue
216     * @param int $maxValue
217     * @return $this
218     */
219    public function requireMaxIfNotNull(string $fieldName, int $fieldValue, int $maxValue): self
220    {
221        if ($fieldValue > $maxValue) {
222            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::FIELD_VALUE_TOO_BIG, ["max" => $maxValue]));
223        }
224        return $this;
225    }
226
227    public function requireValidUuidV4(string $fieldName, string $fieldValue): self
228    {
229        if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $fieldValue)) {
230            $this->validationErrors->add(new ValidationError($fieldName, ErrorCode::INVALID_UUID));
231        }
232
233        return $this;
234    }
235
236    /**
237     * @param string $fieldName
238     * @param callable():bool $supplier
239     * @param BaseErrorCode $errorCode
240     * @return $this
241     */
242    public function require(string $fieldName, callable $supplier, BaseErrorCode $errorCode): self
243    {
244        if (true !== $supplier()) {
245            $this->validationErrors->add(new ValidationError($fieldName, $errorCode));
246        }
247        return $this;
248    }