1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace BrenoRoosevelt\Validation\Rules\Brazilian; |
5
|
|
|
|
6
|
|
|
use Attribute; |
7
|
|
|
use BrenoRoosevelt\Validation\AbstractValidation; |
8
|
|
|
use Throwable; |
9
|
|
|
|
10
|
|
|
#[Attribute(Attribute::TARGET_PROPERTY)] |
11
|
|
|
abstract class Document extends AbstractValidation |
12
|
|
|
{ |
13
|
|
|
public function __construct(private bool $mask = true, ?string $message = 'Documento inválido') |
14
|
|
|
{ |
15
|
|
|
parent::__construct($message); |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
public function evaluate($input, array $context = []): bool |
19
|
|
|
{ |
20
|
|
|
try { |
21
|
|
|
$document = (string) $input; |
22
|
|
|
} catch (Throwable) { |
|
|
|
|
23
|
|
|
return false; |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
if ($this->mask) { |
27
|
|
|
if (!$this->isValidMask($document)) { |
28
|
|
|
return false; |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
$document = $this->unmaskNumber($document); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
$document = $this->adjustZeroPadding($document); |
35
|
|
|
return $this->isValidDocument($document); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
protected function isValidMask(string $input): bool |
39
|
|
|
{ |
40
|
|
|
return preg_match($this->maskPattern(), $input) === 1; |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
protected function unmaskNumber(string $input): string |
44
|
|
|
{ |
45
|
|
|
return preg_replace('/\D/', '', $input); |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
protected function adjustZeroPadding(string $input): string |
49
|
|
|
{ |
50
|
|
|
return str_pad($input, $this->unmaskedLength(), '0', STR_PAD_LEFT); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
protected function validateNumbersWithCorrectLength(string $unmaskedInput): bool |
54
|
|
|
{ |
55
|
|
|
$numericWithSize = '/^\d{' . $this->unmaskedLength() . '}$/'; |
56
|
|
|
return preg_match($numericWithSize, $unmaskedInput) === 1; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
protected function validateCpfCnpjDigits(string $unmaskedDocument): bool |
60
|
|
|
{ |
61
|
|
|
$number = substr($unmaskedDocument, 0, -2); |
62
|
|
|
$digits = substr($unmaskedDocument, -2); |
63
|
|
|
|
64
|
|
|
$digit1 = DigitoVerificador::mod11($number); |
65
|
|
|
$digit2 = DigitoVerificador::mod11($number . $digit1); |
66
|
|
|
|
67
|
|
|
return $digits === ($digit1 . $digit2); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
abstract protected function isValidDocument(string $input): bool; |
71
|
|
|
|
72
|
|
|
abstract protected function maskPattern(): string; |
73
|
|
|
|
74
|
|
|
abstract protected function unmaskedLength(): int; |
75
|
|
|
} |
76
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.