Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — master ( 2bcc16...e2677d )
by Henrique
02:11
created

NestedValidationException   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Test Coverage

Coverage 24.14%

Importance

Changes 0
Metric Value
dl 0
loc 282
ccs 28
cts 116
cp 0.2414
rs 8.3999
c 0
b 0
f 0
wmc 46

14 Methods

Rating   Name   Duplication   Size   Complexity  
A findRelated() 0 11 3
A isRelated() 0 3 2
A getRecursiveIterator() 0 9 1
A addRelated() 0 5 1
A getRelated() 0 7 2
B findMessages() 0 28 6
A setRelated() 0 7 2
A getMessages() 0 12 3
C getIterator() 0 44 8
A isOmissible() 0 11 3
A setParam() 0 11 3
A getExceptionForPath() 0 15 4
A getRelatedByName() 0 9 4
A getFullMessage() 0 17 4

How to fix   Complexity   

Complex Class

Complex classes like NestedValidationException often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use NestedValidationException, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of Respect/Validation.
5
 *
6
 * (c) Alexandre Gomes Gaigalas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the "LICENSE.md"
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Respect\Validation\Exceptions;
15
16
use IteratorAggregate;
17
use RecursiveIteratorIterator;
18
use SplObjectStorage;
19
20
class NestedValidationException extends ValidationException implements IteratorAggregate
21
{
22
    /**
23
     * @var SplObjectStorage
24
     */
25
    private $exceptions = [];
26
27
    /**
28
     * @param ValidationException $exception
29
     *
30
     * @return self
31
     */
32 3
    public function addRelated(ValidationException $exception)
33
    {
34 3
        $this->getRelated()->attach($exception);
35
36 3
        return $this;
37
    }
38
39
    /**
40
     * @param string              $path
41
     * @param ValidationException $exception
42
     *
43
     * @return ValidationException
44
     */
45
    private function getExceptionForPath($path, ValidationException $exception)
46
    {
47
        if ($path === $exception->guessId()) {
48
            return $exception;
49
        }
50
51
        if (!$exception instanceof self) {
52
            return $exception;
53
        }
54
55
        foreach ($exception as $subException) {
56
            return $subException;
57
        }
58
59
        return $exception;
60
    }
61
62
    /**
63
     * @param array $paths
64
     *
65
     * @return string[]
66
     */
67
    public function findMessages(array $paths)
68
    {
69
        $messages = [];
70
71
        foreach ($paths as $key => $value) {
72
            $numericKey = is_numeric($key);
73
            $path = $numericKey ? $value : $key;
74
75
            if (!($exception = $this->getRelatedByName($path))) {
76
                $exception = $this->findRelated($path);
77
            }
78
79
            $path = str_replace('.', '_', $path);
80
81
            if (!$exception) {
82
                $messages[$path] = '';
83
                continue;
84
            }
85
86
            $exception = $this->getExceptionForPath($path, $exception);
87
            if (!$numericKey) {
88
                $exception->setTemplate($value);
89
            }
90
91
            $messages[$path] = $exception->getMainMessage();
92
        }
93
94
        return $messages;
95
    }
96
97
    /**
98
     * @return Exception
99
     */
100 1
    public function findRelated($path)
101
    {
102 1
        $target = $this;
103 1
        $pieces = explode('.', $path);
104
105 1
        while (!empty($pieces) && $target) {
106 1
            $piece = array_shift($pieces);
107 1
            $target = $target->getRelatedByName($piece);
108
        }
109
110 1
        return $target;
111
    }
112
113
    /**
114
     * @return RecursiveIteratorIterator
115
     */
116 1
    private function getRecursiveIterator()
117
    {
118 1
        $exceptionIterator = new RecursiveExceptionIterator($this);
119 1
        $recursiveIteratorIterator = new RecursiveIteratorIterator(
120 1
            $exceptionIterator,
121 1
            RecursiveIteratorIterator::SELF_FIRST
122
        );
123
124 1
        return $recursiveIteratorIterator;
125
    }
126
127
    /**
128
     * Returns weather an exception should be omitted or not.
129
     *
130
     * @param ExceptionInterface $exception
131
     *
132
     * @return bool
133
     */
134
    private function isOmissible(ExceptionInterface $exception)
135
    {
136
        if (!$exception instanceof self) {
137
            return false;
138
        }
139
140
        $relatedExceptions = $exception->getRelated();
141
        $relatedExceptions->rewind();
142
        $childException = $relatedExceptions->current();
143
144
        return 1 === $relatedExceptions->count() && !$childException instanceof NonOmissibleExceptionInterface;
145
    }
146
147
    /**
148
     * @return SplObjectStorage
149
     */
150
    public function getIterator()
151
    {
152
        $childrenExceptions = new SplObjectStorage();
153
154
        $recursiveIteratorIterator = $this->getRecursiveIterator();
155
        $exceptionIterator = $recursiveIteratorIterator->getInnerIterator();
156
157
        $lastDepth = 0;
158
        $lastDepthOriginal = 0;
159
        $knownDepths = [];
160
        foreach ($recursiveIteratorIterator as $childException) {
161
            if ($this->isOmissible($childException)) {
162
                continue;
163
            }
164
165
            $currentDepth = $lastDepth;
166
            $currentDepthOriginal = $recursiveIteratorIterator->getDepth() + 1;
167
168
            if (isset($knownDepths[$currentDepthOriginal])) {
169
                $currentDepth = $knownDepths[$currentDepthOriginal];
170
            } elseif ($currentDepthOriginal > $lastDepthOriginal
171
                && ($this->hasCustomTemplate() || 1 != $exceptionIterator->count())) {
0 ignored issues
show
Bug introduced by
The method count() does not exist on Iterator. It seems like you code against a sub-type of Iterator such as SplDoublyLinkedList or HttpMessage or HttpRequestPool or Zend\Stdlib\PriorityList or SplFixedArray or SplObjectStorage or SQLiteResult or Imagick or TheSeer\Tokenizer\TokenCollection or SplPriorityQueue or MongoCursor or Zend\Stdlib\FastPriorityQueue or SplHeap or MongoGridFSCursor or CachingIterator or PHP_Token_Stream or Phar or ArrayIterator or GlobIterator or Phar or Phar or Respect\Validation\Excep...ursiveExceptionIterator or RecursiveCachingIterator or RecursiveArrayIterator or SimpleXMLIterator or Phar. ( Ignorable by Annotation )

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

171
                && ($this->hasCustomTemplate() || 1 != $exceptionIterator->/** @scrutinizer ignore-call */ count())) {
Loading history...
172
                ++$currentDepth;
173
            }
174
175
            if (!isset($knownDepths[$currentDepthOriginal])) {
176
                $knownDepths[$currentDepthOriginal] = $currentDepth;
177
            }
178
179
            $lastDepth = $currentDepth;
180
            $lastDepthOriginal = $currentDepthOriginal;
181
182
            $childrenExceptions->attach(
183
                $childException,
184
                [
185
                    'depth' => $currentDepth,
186
                    'depth_original' => $currentDepthOriginal,
187
                    'previous_depth' => $lastDepth,
188
                    'previous_depth_original' => $lastDepthOriginal,
189
                ]
190
            );
191
        }
192
193
        return $childrenExceptions;
194
    }
195
196
    /**
197
     * @return array
198
     */
199
    public function getMessages()
200
    {
201
        $messages = [$this->getMessage()];
202
        foreach ($this as $exception) {
203
            $messages[] = $exception->getMessage();
204
        }
205
206
        if (count($messages) > 1) {
207
            array_shift($messages);
208
        }
209
210
        return $messages;
211
    }
212
213
    /**
214
     * @return string
215
     */
216
    public function getFullMessage()
217
    {
218
        $marker = '-';
219
        $messages = [];
220
        $exceptions = $this->getIterator();
221
222
        if ($this->hasCustomTemplate() || 1 != count($exceptions)) {
223
            $messages[] = sprintf('%s %s', $marker, $this->getMessage());
224
        }
225
226
        foreach ($exceptions as $exception) {
227
            $depth = $exceptions[$exception]['depth'];
228
            $prefix = str_repeat(' ', $depth * 2);
229
            $messages[] = sprintf('%s%s %s', $prefix, $marker, $exception->getMessage());
230
        }
231
232
        return implode(PHP_EOL, $messages);
233
    }
234
235
    /**
236
     * @return SplObjectStorage
237
     */
238 3
    public function getRelated()
239
    {
240 3
        if (!$this->exceptions instanceof SplObjectStorage) {
0 ignored issues
show
introduced by
$this->exceptions is always a sub-type of SplObjectStorage.
Loading history...
241 3
            $this->exceptions = new SplObjectStorage();
242
        }
243
244 3
        return $this->exceptions;
245
    }
246
247
    /**
248
     * @param string $name
249
     * @param mixed  $value
250
     *
251
     * @return self
252
     */
253
    public function setParam($name, $value)
254
    {
255
        if ('translator' === $name) {
256
            foreach ($this->getRelated() as $exception) {
257
                $exception->setParam($name, $value);
258
            }
259
        }
260
261
        parent::setParam($name, $value);
262
263
        return $this;
264
    }
265
266
    /**
267
     * @return bool
268
     */
269 1
    private function isRelated($name, ValidationException $exception)
270
    {
271 1
        return $exception->getId() === $name || $exception->getName() === $name;
272
    }
273
274
    /**
275
     * @return ValidationException
276
     */
277 1
    public function getRelatedByName($name)
278
    {
279 1
        if ($this->isRelated($name, $this)) {
280
            return $this;
281
        }
282
283 1
        foreach ($this->getRecursiveIterator() as $exception) {
284 1
            if ($this->isRelated($name, $exception)) {
285 1
                return $exception;
286
            }
287
        }
288 1
    }
289
290
    /**
291
     * @param array $exceptions
292
     *
293
     * @return self
294
     */
295
    public function setRelated(array $exceptions)
296
    {
297
        foreach ($exceptions as $exception) {
298
            $this->addRelated($exception);
299
        }
300
301
        return $this;
302
    }
303
}
304