Passed
Pull Request — master (#1181)
by Tarmo
06:39 queued 03:09
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 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
c 0
b 0
f 0
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 Closure;
13
use Doctrine\ORM\EntityNotFoundException;
14
use Psr\Log\LoggerInterface;
15
use Symfony\Component\Validator\Constraint;
16
use Symfony\Component\Validator\ConstraintValidator;
17
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
18
use Symfony\Component\Validator\Exception\UnexpectedValueException;
19
use function array_filter;
20
use function array_map;
21
use function count;
22
use function get_class;
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 LoggerInterface $logger,
37
    ) {
38 8
    }
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 8
    public function validate($value, Constraint $constraint): void
44
    {
45 8
        if (!$constraint instanceof EntityReferenceExists) {
46 1
            throw new UnexpectedTypeException($constraint, EntityReferenceExists::class);
47
        }
48
49 7
        $values = $this->normalize($constraint->entityClass, $value);
50
51 2
        $this->check($values);
52 2
    }
53
54
    /**
55
     * Checks if the passed value is valid.
56
     *
57
     * @param EntityInterface|array<int, EntityInterface>|mixed $input
58
     *
59
     * @return array<int, EntityInterface>
60
     */
61 7
    private function normalize(string $target, mixed $input): array
62
    {
63 7
        $values = is_array($input) ? $input : [$input];
64
65 7
        foreach ($values as $value) {
66 7
            if (!$value instanceof $target) {
67 4
                throw new UnexpectedValueException($value, $target);
68
            }
69
70 3
            if (!$value instanceof EntityInterface) {
71 1
                throw new UnexpectedValueException($value, EntityInterface::class);
72
            }
73
        }
74
75 2
        return $values;
76
    }
77
78
    /**
79
     * @param array<int, EntityInterface> $entities
80
     */
81 2
    private function check(array $entities): void
82
    {
83 2
        $invalidIds = $this->getInvalidValues($entities);
84
85 2
        if (!empty($invalidIds)) {
86 1
            $message = count($invalidIds) === 1
87 1
                ? EntityReferenceExists::MESSAGE_SINGLE
88
                : EntityReferenceExists::MESSAGE_MULTIPLE;
89 1
            $entity = get_class($entities[0]);
90
91 1
            $parameterEntity = str_replace('Proxies\\__CG__\\', '', $entity);
92 1
            $parameterId = count($invalidIds) > 1 ? implode('", "', $invalidIds) : $invalidIds[0];
93
94 1
            $this->context
95 1
                ->buildViolation($message)
96 1
                ->setParameter('{{ entity }}', $parameterEntity)
97 1
                ->setParameter('{{ id }}', $parameterId)
98 1
                ->setCode(EntityReferenceExists::ENTITY_REFERENCE_EXISTS_ERROR)
99 1
                ->addViolation();
100
        }
101 2
    }
102
103
    /**
104
     * @param array<int, EntityInterface> $entities
105
     *
106
     * @return array<int, string>
107
     */
108 2
    private function getInvalidValues(array $entities): array
109
    {
110 2
        return array_map(
111 2
            static fn (EntityInterface $entity): string => $entity->getId(),
112 2
            array_filter($entities, $this->getFilterClosure())
113
        );
114
    }
115
116
    /**
117
     * Method to return used filter closure.
118
     */
119 2
    private function getFilterClosure(): Closure
120
    {
121 2
        return function (EntityInterface $entity): bool {
122 2
            $output = false;
123
124
            try {
125 2
                $entity->getCreatedAt();
126 1
            } catch (EntityNotFoundException $exception) {
127 1
                $this->logger->error($exception->getMessage());
128
129 1
                $output = true;
130
            }
131
132 2
            return $output;
133 2
        };
134
    }
135
}
136