Completed
Push — master ( ce4c5c...ef565d )
by Tarmo
09:52 queued 09:47
created

EntityReferenceExistsValidator   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 97
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 35
c 1
b 0
f 0
dl 0
loc 97
ccs 44
cts 44
cp 1
rs 10
wmc 14

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A check() 0 17 4
A normalize() 0 15 4
A getFilterClosure() 0 14 2
A getInvalidValues() 0 5 1
A validate() 0 9 2
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/App/Validator/Constraints/EntityReferenceExistsValidator.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\Validator\Constraints;
10
11
use App\Entity\Interfaces\EntityInterface;
12
use App\Validator\Constraints\EntityReferenceExists as Constraint;
13
use Closure;
14
use Doctrine\ORM\EntityNotFoundException;
15
use Psr\Log\LoggerInterface;
16
use Symfony\Component\Validator\Constraint as BaseConstraint;
17
use Symfony\Component\Validator\ConstraintValidator;
18
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
19
use Symfony\Component\Validator\Exception\UnexpectedValueException;
20
use function array_filter;
21
use function array_map;
22
use function count;
23
use function implode;
24
use function is_array;
25
use function str_replace;
26
27
/**
28
 * Class EntityReferenceExistsValidator
29
 *
30
 * @package App\Validator\Constraints
31
 * @author TLe, Tarmo Leppänen <[email protected]>
32
 */
33
class EntityReferenceExistsValidator extends ConstraintValidator
34
{
35 8
    public function __construct(
36
        private readonly LoggerInterface $logger,
37
    ) {
38 8
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 8
    public function validate(mixed $value, BaseConstraint $constraint): void
44
    {
45 8
        if (!$constraint instanceof Constraint) {
46 1
            throw new UnexpectedTypeException($constraint, Constraint::class);
47
        }
48
49 7
        $values = $this->normalize($constraint->entityClass, $value);
50
51 2
        $this->check($values);
52
    }
53
54
    /**
55
     * Checks if the passed value is valid.
56
     *
57
     * @return array<array-key, EntityInterface>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, EntityInterface> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, EntityInterface>.
Loading history...
58
     */
59 7
    private function normalize(string $target, mixed $input): array
60
    {
61 7
        return array_map(
62 7
            static function ($value) use ($target) {
63 7
                if (!$value instanceof $target) {
64 4
                    throw new UnexpectedValueException($value, $target);
65
                }
66
67 3
                if (!$value instanceof EntityInterface) {
68 1
                    throw new UnexpectedValueException($value, EntityInterface::class);
69
                }
70
71 2
                return $value;
72 7
            },
73 7
            is_array($input) ? $input : [$input]
74 7
        );
75
    }
76
77
    /**
78
     * @param array<array-key, EntityInterface> $entities
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, EntityInterface> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, EntityInterface>.
Loading history...
79
     */
80 2
    private function check(array $entities): void
81
    {
82 2
        $invalidIds = $this->getInvalidValues($entities);
83
84 2
        if ($invalidIds !== []) {
85 1
            $message = count($invalidIds) === 1 ? Constraint::MESSAGE_SINGLE : Constraint::MESSAGE_MULTIPLE;
86 1
            $entity = $entities[0]::class;
87
88 1
            $parameterEntity = str_replace('Proxies\\__CG__\\', '', $entity);
89 1
            $parameterId = count($invalidIds) > 1 ? implode('", "', $invalidIds) : $invalidIds[0];
90
91 1
            $this->context
92 1
                ->buildViolation($message)
93 1
                ->setParameter('{{ entity }}', $parameterEntity)
94 1
                ->setParameter('{{ id }}', $parameterId)
95 1
                ->setCode(Constraint::ENTITY_REFERENCE_EXISTS_ERROR)
96 1
                ->addViolation();
97
        }
98
    }
99
100
    /**
101
     * @param array<array-key, EntityInterface> $entities
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, EntityInterface> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, EntityInterface>.
Loading history...
102
     *
103
     * @return array<array-key, string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, string>.
Loading history...
104
     */
105 2
    private function getInvalidValues(array $entities): array
106
    {
107 2
        return array_map(
108 2
            static fn (EntityInterface $entity): string => $entity->getId(),
109 2
            array_filter($entities, $this->getFilterClosure())
110 2
        );
111
    }
112
113
    /**
114
     * Method to return used filter closure.
115
     */
116 2
    private function getFilterClosure(): Closure
117
    {
118 2
        return function (EntityInterface $entity): bool {
119 2
            $output = false;
120
121
            try {
122 2
                $entity->getCreatedAt();
123 1
            } catch (EntityNotFoundException $exception) {
124 1
                $this->logger->error($exception->getMessage());
125
126 1
                $output = true;
127
            }
128
129 2
            return $output;
130 2
        };
131
    }
132
}
133