| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- <?php
- namespace App\ValueObjects;
- use App\Casts\CnpjCast;
- use Closure;
- use Illuminate\Contracts\Database\Eloquent\Castable;
- use InvalidArgumentException;
- use JsonSerializable;
- use Stringable;
- final readonly class Cnpj implements Castable, JsonSerializable, Stringable
- {
- private string $value;
- public function __construct(string $value)
- {
- $normalized = preg_replace('/[^A-Z0-9]/i', '', $value);
- $normalized = $normalized === null ? null : strtoupper($normalized);
- if ($normalized === null || ! self::isValid($normalized)) {
- throw new InvalidArgumentException(__('validation.cnpj'));
- }
- $this->value = $normalized;
- }
- public static function castUsing(array $arguments): string
- {
- return CnpjCast::class;
- }
- public static function rule(): Closure
- {
- return static function (string $attribute, mixed $value, Closure $fail): void {
- if (! is_string($value)) {
- $fail(__('validation.cnpj'));
- return;
- }
- try {
- new self($value);
- } catch (InvalidArgumentException) {
- $fail(__('validation.cnpj'));
- }
- };
- }
- public function value(): string
- {
- return $this->value;
- }
- public function formatted(): string
- {
- return preg_replace(
- '/^(.{2})(.{3})(.{3})(.{4})(\d{2})$/',
- '$1.$2.$3/$4-$5',
- $this->value,
- );
- }
- public function __toString(): string
- {
- return $this->value;
- }
- public function jsonSerialize(): string
- {
- return $this->value;
- }
- private static function isValid(string $value): bool
- {
- if (! preg_match('/^[A-Z0-9]{12}\d{2}$/', $value) || preg_match('/^([A-Z0-9])\1{13}$/', $value)) {
- return false;
- }
- $base = substr($value, 0, 12);
- $firstDigit = self::checkDigit($base);
- $secondDigit = self::checkDigit($base.$firstDigit);
- return hash_equals($base.$firstDigit.$secondDigit, $value);
- }
- private static function checkDigit(string $value): int
- {
- $sum = 0;
- $weight = 2;
- for ($index = strlen($value) - 1; $index >= 0; $index--) {
- $sum += (ord($value[$index]) - 48) * $weight;
- $weight = $weight === 9 ? 2 : $weight + 1;
- }
- $remainder = $sum % 11;
- return $remainder < 2 ? 0 : 11 - $remainder;
- }
- }
|