ValidationParser::buildValidation()   D
last analyzed

Complexity

Conditions 9
Paths 16

Size

Total Lines 41
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 41
rs 4.909
cc 9
eloc 33
nc 16
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Kreta package.
5
 *
6
 * (c) Beñat Espiña <[email protected]>
7
 * (c) Gorka Laucirica <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Kreta\SimpleApiDocBundle\Parser;
14
15
use Nelmio\ApiDocBundle\Parser\ValidationParser as BaseValidationParser;
16
use Symfony\Component\Validator\Constraint;
17
use Symfony\Component\Validator\Constraints\Count;
18
use Symfony\Component\Validator\Constraints\Length;
19
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
20
use Symfony\Component\Validator\Validator\ValidatorInterface;
21
22
/**
23
 * Validation parser class.
24
 *
25
 * @author Beñat Espiña <[email protected]>
26
 */
27
class ValidationParser extends BaseValidationParser
28
{
29
    /**
30
     * The Symfony validator component.
31
     *
32
     * @var \Symfony\Component\Validator\Validator\ValidatorInterface
33
     */
34
    protected $validator;
35
36
    /**
37
     * Constructor.
38
     *
39
     * @param MetadataFactoryInterface $factory   The metadata factory
40
     * @param ValidatorInterface       $validator The Symfony validator component
41
     */
42
    public function __construct(MetadataFactoryInterface $factory, ValidatorInterface $validator)
43
    {
44
        parent::__construct($factory);
45
        $this->validator = $validator;
46
    }
47
48
    /**
49
     * Gets the validations.
50
     *
51
     * @param string|null $class The class namespace
52
     *
53
     * @return array
54
     */
55
    public function getValidations($class = null)
56
    {
57
        $reflectionClass = $class ? new \ReflectionClass($class) : false;
58
        if ($reflectionClass === false) {
59
            return [];
60
        }
61
        $result = $this->buildValidation($class);
62
        $validations = [];
63
        foreach ($result as $keyElement => $element) {
64
            if (is_array($element)) {
65
                foreach ($element as $keyChild => $child) {
66
                    if (is_array($child)) {
67
                        foreach ($child as $grandChild) {
68
                            $validations[] = sprintf('%s => %s', $keyChild, $grandChild);
69
                        }
70
                    } else {
71
                        $validations[] = sprintf('%s => %s', $keyElement, $child);
72
                    }
73
                }
74
            } else {
75
                $validations[] = $element;
76
            }
77
        }
78
79
        return $validations;
80
    }
81
82
    /**
83
     * Parses and builds the validation.
84
     *
85
     * @param string|null $class The class namespace
86
     *
87
     * @return array
88
     */
89
    protected function buildValidation($class = null)
90
    {
91
        $validations = [];
92
        $metadata = $this->validator->getMetadataFor($class);
93
        $entityConstraints = [];
94
        foreach ($metadata->getConstraints() as $constraint) {
95
            $class = new \ReflectionClass($constraint);
96
            $fields = $constraint->fields;
97
            $entityConstraint = [implode(', ', (array) $fields) => $constraint->message];
98
            $entityConstraints = array_merge($entityConstraints, $entityConstraint);
99
            $validations[$class->getShortName()] = $entityConstraint;
100
        }
101
102
        foreach ($metadata->getConstrainedProperties() as $property) {
103
            $constraints = $metadata->getPropertyMetadata($property)[0]->constraints;
104
            $result = [];
105
            foreach ($constraints as $constraint) {
106
                $class = new \ReflectionObject($constraint);
107
                switch ($name = $class->getShortName()) {
108
                    case 'True':
109
                        $result[$name] = $constraint->message;
110
                        break;
111
                    case 'NotBlank':
112
                        $result[$name] = $constraint->message;
113
                        break;
114
                    case 'Type':
115
                        $result[$name] = $constraint->type;
116
                        break;
117
                    case 'Length':
118
                        $result[$name] = $this->constraintMessages($constraint);
119
                        break;
120
                    case 'Count':
121
                        $result[$name] = $this->constraintMessages($constraint);
122
                        break;
123
                }
124
            }
125
            $validations[$property] = $result;
126
        }
127
128
        return $validations;
129
    }
130
131
    /**
132
     * Parses the constraint message.
133
     *
134
     * @param \Symfony\Component\Validator\Constraint $constraint The constraint
135
     *
136
     * @return array
137
     */
138
    protected function constraintMessages(Constraint $constraint)
139
    {
140
        $result = [];
141 View Code Duplication
        if (isset($constraint->min) && $constraint->min !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
            $count = new Count(['min' => $constraint->min]);
143
            $length = new Length(['min' => $constraint->min]);
144
            $result[] = $constraint->minMessage;
145
        }
146 View Code Duplication
        if (isset($constraint->max) && $constraint->max !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
147
            $count = new Count(['max' => $constraint->min]);
148
            $length = new Length(['max' => $constraint->min]);
149
            $result[] = $constraint->maxMessage;
150
        }
151
        if (isset($constraint->exactMessage)
152
            && $constraint->exactMessage !== $count->exactMessage
0 ignored issues
show
Bug introduced by
The variable $count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
153
            && $constraint->exactMessage !== $length->exactMessage
0 ignored issues
show
Bug introduced by
The variable $length does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
154
        ) {
155
            $result[] = $constraint->exactMessage;
156
        }
157
158
        return $result;
159
    }
160
}
161