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

Completed
Pull Request — master (#957)
by Henrique
02:18
created

NestedValidationException::getMessages()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 0
cts 17
cp 0
rs 8.439
c 0
b 0
f 0
cc 5
eloc 16
nc 8
nop 1
crap 30
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 function array_map;
17
use function array_unshift;
18
use function count;
19
use Exception;
20
use function explode;
21
use function is_array;
22
use function is_numeric;
23
use function is_string;
24
use IteratorAggregate;
25
use RecursiveIteratorIterator;
26
use SplObjectStorage;
27
use function var_dump;
28
29
class NestedValidationException extends ValidationException implements IteratorAggregate
30
{
31
    /**
32
     * @var SplObjectStorage
33
     */
34
    private $exceptions = [];
35
36
    /**
37
     * @param ValidationException $exception
38
     *
39
     * @return self
40
     */
41
    public function addRelated(ValidationException $exception)
42
    {
43
        $this->getRelated()->attach($exception);
44
45
        return $this;
46
    }
47
48
    /**
49
     * @return RecursiveIteratorIterator
50
     */
51
    private function getRecursiveIterator()
52
    {
53
        $exceptionIterator = new RecursiveExceptionIterator($this);
54
        $recursiveIteratorIterator = new RecursiveIteratorIterator(
55
            $exceptionIterator,
56
            RecursiveIteratorIterator::SELF_FIRST
57
        );
58
59
        return $recursiveIteratorIterator;
60
    }
61
62
    /**
63
     * Returns weather an exception should be omitted or not.
64
     *
65
     * @param ExceptionInterface $exception
66
     *
67
     * @return bool
68
     */
69
    private function isOmissible(ExceptionInterface $exception)
70
    {
71
        if (!$exception instanceof self) {
72
            return false;
73
        }
74
75
        $relatedExceptions = $exception->getRelated();
76
        $relatedExceptions->rewind();
77
        $childException = $relatedExceptions->current();
78
79
        return 1 === $relatedExceptions->count() && !$childException instanceof NonOmissibleExceptionInterface;
80
    }
81
82
    /**
83
     * @return SplObjectStorage
84
     */
85
    public function getIterator()
86
    {
87
        $childrenExceptions = new SplObjectStorage();
88
89
        $recursiveIteratorIterator = $this->getRecursiveIterator();
90
        $exceptionIterator = $recursiveIteratorIterator->getInnerIterator();
91
92
        $lastDepth = 0;
93
        $lastDepthOriginal = 0;
94
        $knownDepths = [];
95
        foreach ($recursiveIteratorIterator as $childException) {
96
            if ($this->isOmissible($childException)) {
97
                continue;
98
            }
99
100
            $currentDepth = $lastDepth;
101
            $currentDepthOriginal = $recursiveIteratorIterator->getDepth() + 1;
102
103
            if (isset($knownDepths[$currentDepthOriginal])) {
104
                $currentDepth = $knownDepths[$currentDepthOriginal];
105
            } elseif ($currentDepthOriginal > $lastDepthOriginal
106
                && ($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 Yaf_Config_Simple or SplFixedArray or SplObjectStorage or Yaf\Session or SQLiteResult or Imagick or TheSeer\Tokenizer\TokenCollection or Yaf_Session or SplPriorityQueue or Yaf\Config\Simple or Yaf\Config\Ini or MongoCursor or Zend\Stdlib\FastPriorityQueue or Yaf_Config_Ini 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

106
                && ($this->hasCustomTemplate() || 1 != $exceptionIterator->/** @scrutinizer ignore-call */ count())) {
Loading history...
107
                ++$currentDepth;
108
            }
109
110
            if (!isset($knownDepths[$currentDepthOriginal])) {
111
                $knownDepths[$currentDepthOriginal] = $currentDepth;
112
            }
113
114
            $lastDepth = $currentDepth;
115
            $lastDepthOriginal = $currentDepthOriginal;
116
117
            $childrenExceptions->attach(
118
                $childException,
119
                [
120
                    'depth' => $currentDepth,
121
                    'depth_original' => $currentDepthOriginal,
122
                    'previous_depth' => $lastDepth,
123
                    'previous_depth_original' => $lastDepthOriginal,
124
                ]
125
            );
126
        }
127
128
        return $childrenExceptions;
129
    }
130
131
    public function getMessages(array $replacements = []): array
132
    {
133
        $messages = [$this->getId() => $this->renderMessage($this, $this->getId(), $replacements)];
134
        foreach ($this->getRelated() as $exception) {
135
            $id = $exception->getId();
136
            if (!$exception instanceof self) {
137
                $messages[$id] = $this->renderMessage(
138
                    $exception,
139
                    $id,
140
                    $this->findReplacements($replacements, $this->getId())
141
                );
142
                continue;
143
            }
144
145
            $messages[$id] = $exception->getMessages($this->findReplacements($replacements, $id, $this->getId()));
146
            if (count($messages[$id]) > 1) {
0 ignored issues
show
Bug introduced by
$messages[$id] of type string is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

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

146
            if (count(/** @scrutinizer ignore-type */ $messages[$id]) > 1) {
Loading history...
147
                continue;
148
            }
149
150
            $messages[$id] = current($messages[$exception->getId()]);
0 ignored issues
show
Bug introduced by
$messages[$exception->getId()] of type string is incompatible with the type array expected by parameter $array of current(). ( Ignorable by Annotation )

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

150
            $messages[$id] = current(/** @scrutinizer ignore-type */ $messages[$exception->getId()]);
Loading history...
151
        }
152
153
        if (count($messages) > 1) {
154
            unset($messages[$this->getId()]);
155
        }
156
157
        return $messages;
158
    }
159
160
    /**
161
     * @return string
162
     */
163
    public function getFullMessage()
164
    {
165
        $marker = '-';
166
        $messages = [];
167
        $exceptions = $this->getIterator();
168
169
        if ($this->hasCustomTemplate() || 1 != count($exceptions)) {
170
            $messages[] = sprintf('%s %s', $marker, $this->getMessage());
171
        }
172
173
        foreach ($exceptions as $exception) {
174
            $depth = $exceptions[$exception]['depth'];
175
            $prefix = str_repeat(' ', $depth * 2);
176
            $messages[] = sprintf('%s%s %s', $prefix, $marker, $exception->getMessage());
177
        }
178
179
        return implode(PHP_EOL, $messages);
180
    }
181
182
    /**
183
     * @return SplObjectStorage
184
     */
185
    public function getRelated()
186
    {
187
        if (!$this->exceptions instanceof SplObjectStorage) {
0 ignored issues
show
introduced by
$this->exceptions is always a sub-type of SplObjectStorage. If $this->exceptions can have other possible types, add them to library/Exceptions/NestedValidationException.php:32.
Loading history...
188
            $this->exceptions = new SplObjectStorage();
189
        }
190
191
        return $this->exceptions;
192
    }
193
194
    /**
195
     * @param array $exceptions
196
     *
197
     * @return self
198
     */
199
    public function setRelated(array $exceptions)
200
    {
201
        foreach ($exceptions as $exception) {
202
            $this->addRelated($exception);
203
        }
204
205
        return $this;
206
    }
207
208
    private function renderMessage(ValidationException $exception, $id, array $replacements): string
209
    {
210
        if (isset($replacements[$id])) {
211
            $exception->updateTemplate($replacements[$id]);
212
        }
213
214
        return $exception->getMessage();
215
    }
216
217
    private function findReplacements(array $replacements, ...$ids): array
218
    {
219
        while (count($ids) > 0) {
220
            $id = array_shift($ids);
221
            if (isset($replacements[$id]) && is_array($replacements[$id])) {
222
                $replacements = $replacements[$id];
223
            }
224
        }
225
226
        return $replacements;
227
    }
228
}
229