ValidationAnnotation::enterNode()   B
last analyzed

Complexity

Conditions 11
Paths 15

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 11.1043

Importance

Changes 0
Metric Value
dl 0
loc 43
c 0
b 0
f 0
ccs 19
cts 21
cp 0.9048
rs 7.3166
cc 11
nc 15
nop 1
crap 11.1043

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the PHP Translation package.
5
 *
6
 * (c) PHP Translation team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Translation\Extractor\Visitor\Php\Symfony;
13
14
use Doctrine\Common\Annotations\AnnotationException;
15
use PhpParser\Node;
16
use PhpParser\NodeVisitor;
17
use Symfony\Component\Validator\Mapping\ClassMetadata;
18
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
19
use Translation\Extractor\Visitor\Php\BasePHPVisitor;
20
21
/**
22
 * @author Tobias Nyholm <[email protected]>
23
 */
24
final class ValidationAnnotation extends BasePHPVisitor implements NodeVisitor
25
{
26
    /**
27
     * @var MetadataFactoryInterface
28
     */
29
    private $metadataFactory;
30
31
    /**
32
     * @var string
33
     */
34
    private $namespace;
35
36 2
    public function __construct(MetadataFactoryInterface $metadataFactory)
37
    {
38 2
        $this->metadataFactory = $metadataFactory;
39 2
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44 2
    public function beforeTraverse(array $nodes): ?Node
45
    {
46 2
        $this->namespace = '';
47
48 2
        return null;
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54 2
    public function enterNode(Node $node): ?Node
55
    {
56 2
        if ($node instanceof Node\Stmt\Namespace_) {
57 2
            if (isset($node->name)) {
58
                // save the namespace
59 2
                $this->namespace = implode('\\', $node->name->parts);
60
            }
61
62 2
            return null;
63
        }
64
65 2
        if (!$node instanceof Node\Stmt\Class_) {
66 2
            return null;
67
        }
68
69 2
        $name = '' === $this->namespace ? $node->name : $this->namespace.'\\'.$node->name;
70
71 2
        if (!class_exists($name)) {
72
            return null;
73
        }
74
75
        try {
76
            /** @var ClassMetadata $metadata */
77 2
            $metadata = $this->metadataFactory->getMetadataFor($name);
78 2
        } catch (AnnotationException $e) {
79 2
            $this->addError($node, sprintf('Could not parse class "%s" for annotations. %s', $this->namespace, $e->getMessage()));
80
81 2
            return null;
82
        }
83
84 1
        if (!$metadata->hasConstraints() && !\count($metadata->getConstrainedProperties())) {
85
            return null;
86
        }
87
88 1
        $this->extractFromConstraints($metadata->constraints);
89 1
        foreach ($metadata->members as $members) {
90 1
            foreach ($members as $member) {
91 1
                $this->extractFromConstraints($member->constraints);
92
            }
93
        }
94
95 1
        return null;
96
    }
97
98 1
    private function extractFromConstraints(array $constraints): void
99
    {
100 1
        foreach ($constraints as $constraint) {
101 1
            $ref = new \ReflectionClass($constraint);
102 1
            $defaultValues = $ref->getDefaultProperties();
103
104 1
            $properties = $ref->getProperties();
105
106 1
            foreach ($properties as $property) {
107 1
                $propName = $property->getName();
108
109
                // If the property ends with 'Message'
110 1
                if ('message' === strtolower(substr($propName, -1 * \strlen('Message')))) {
111
                    // If it is different from the default value
112 1
                    if ($defaultValues[$propName] !== $constraint->{$propName}) {
113 1
                        $this->addLocation($constraint->{$propName}, 0, null, ['domain' => 'validators']);
114
                    }
115
                }
116
            }
117
        }
118 1
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 2
    public function leaveNode(Node $node): ?Node
124
    {
125 2
        return null;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 2
    public function afterTraverse(array $nodes): ?Node
132
    {
133 2
        return null;
134
    }
135
}
136