Passed
Push — master ( fbb10f...c0768e )
by Vlad
03:01
created

SchemaValidator   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Test Coverage

Coverage 97.87%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 85
ccs 46
cts 47
cp 0.9787
rs 10
wmc 13

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C validate() 0 72 12
1
<?php
2
/**
3
 * Schema Validator
4
 *
5
 * @author Vlad Shashkov <[email protected]>
6
 * @copyright Copyright (c) 2021, The Myaza Software
7
 */
8
9
declare(strict_types=1);
10
11
namespace SchemaValidator;
12
13
use SchemaValidator\Metadata\ClassMetadataFactoryWrapperInterface;
14
use SchemaValidator\Validator\ValidatorInterface;
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 Symfony\Component\Validator\Util\PropertyPath;
20
21
final class SchemaValidator extends ConstraintValidator
22
{
23
    /**
24
     * SchemaValidator constructor.
25
     *
26
     * @param iterable<ValidatorInterface> $validators
27
     */
28 7
    public function __construct(
29
        private iterable $validators,
30
        private ClassMetadataFactoryWrapperInterface $classMetadataFactory
31
    ) {
32 7
    }
33
34 7
    public function validate(mixed $value, Constraint $constraint): void
35
    {
36 7
        if (!$constraint instanceof Schema) {
37 1
            throw new UnexpectedTypeException($constraint, Schema::class);
38
        }
39
40 6
        if (!is_array($value)) {
41 1
            throw new UnexpectedValueException($value, 'array');
42
        }
43
44 5
        $metadata = $this->classMetadataFactory->getMetadataFor($constraint->type, $value);
45 5
        $mapping  = $metadata->getMapping();
46
47 5
        if ($metadata->isEmpty() && null !== $mapping) {
48 2
            $property = $mapping->getProperty();
49
50 2
            if (!$property->isExits()) {
51 1
                $this->context->buildViolation(Schema::MESSAGE_FILED_MISSING)
52 1
                    ->atPath(PropertyPath::append($constraint->rootPath, $property->getName()))
53 1
                    ->setCode(Schema::MISSING_FILED_CODE)
54 1
                    ->setParameter('{{ field }}', $this->formatValue($property->getName()))
55 1
                    ->setInvalidValue(null)
56 1
                    ->addViolation()
57
                ;
58
59 1
                return;
60
            }
61
62 1
            $this->context->buildViolation(Schema::UNKNOWN_RESOURCE)
63 1
                ->atPath(PropertyPath::append($constraint->rootPath, $property->getName()))
64 1
                ->setParameter('{{ allowed }}', $this->formatValues($mapping->getMapValue()))
65 1
                ->setCode(Schema::UNKNOWN_RESOURCE_CODE)
66 1
                ->setInvalidValue($property->getInvalidValue())
67 1
                ->addViolation()
68
            ;
69
70 1
            return;
71
        }
72
73 3
        $attributes = $metadata->getAttributes();
74
75 3
        foreach ($metadata->getParameters() as $parameter) {
76 3
            $reflectionType = $parameter->getType();
77 3
            $propertyName   = ($attributes[$parameter->name] ?? null)?->getSerializedName() ?? $parameter->name;
0 ignored issues
show
Bug introduced by
The method getSerializedName() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

77
            $propertyName   = ($attributes[$parameter->name] ?? null)?->/** @scrutinizer ignore-call */ getSerializedName() ?? $parameter->name;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
78
79 3
            if (null === $reflectionType) {
80
                continue;
81
            }
82
83 3
            if (!array_key_exists($propertyName, $value) && !$parameter->isOptional()) {
84 1
                $this->context->buildViolation(Schema::MESSAGE_FILED_MISSING)
85 1
                    ->setParameter('{{ field }}', $this->formatValue($propertyName))
86 1
                    ->atPath(PropertyPath::append($constraint->rootPath, $propertyName))
87 1
                    ->setCode(Schema::MISSING_FILED_CODE)
88 1
                    ->setInvalidValue(null)
89 1
                    ->addViolation()
90
                ;
91
92 1
                continue;
93
            }
94
95 2
            foreach ($this->validators as $validator) {
96 1
                if (!$validator->support($reflectionType)) {
97 1
                    continue;
98
                }
99
100 1
                $argument = new Argument($propertyName, $value, $reflectionType);
101 1
                $context  = new Context($constraint->rootPath, $constraint->type, $constraint->strictTypes, $this->context);
102
103 1
                $validator->validate($argument, $context);
104
105 1
                break;
106
            }
107
        }
108 3
    }
109
}
110