Passed
Pull Request — master (#2122)
by Tarmo
07:17
created

EntityReferenceExistsValidator::validate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
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