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
Push — master ( b7043b...985b6f )
by Henrique
03:04
created

NestedValidationException   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Test Coverage

Coverage 98.81%

Importance

Changes 0
Metric Value
wmc 30
eloc 75
dl 0
loc 204
ccs 83
cts 84
cp 0.9881
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A renderMessage() 0 7 2
A findTemplates() 0 10 4
A addChildren() 0 7 2
A getMessages() 0 26 5
B getIterator() 0 33 6
A getChildren() 0 3 1
A isOmissible() 0 21 5
A addChild() 0 5 1
A getRecursiveIterator() 0 5 1
A getFullMessage() 0 21 3
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 current;
17
use IteratorAggregate;
18
use RecursiveIteratorIterator;
19
use function spl_object_hash;
20
use SplObjectStorage;
21
use const PHP_EOL;
22
use function count;
23
use function implode;
24
use function is_array;
25
use function str_repeat;
26
27
/**
28
 * Exception for nested validations.
29
 *
30
 * This exception allows to have exceptions inside itself and providers methods
31
 * to handle them and to retrieve nested messages based on itself and its
32
 * children.
33
 *
34
 * @author Alexandre Gomes Gaigalas <[email protected]>
35
 * @author Henrique Moody <[email protected]>
36
 * @author Jonathan Stewmon <[email protected]>
37
 * @author Wojciech Frącz <[email protected]>
38
 */
39
class NestedValidationException extends ValidationException implements IteratorAggregate
40
{
41
    /**
42
     * @var ValidationException[]
43
     */
44
    private $exceptions = [];
45
46
    /**
47
     * Returns the exceptions that are children of the exception.
48
     *
49
     * @return ValidationException[]
50
     */
51 154
    public function getChildren(): array
52
    {
53 154
        return $this->exceptions;
54
    }
55
56
    /**
57
     * Adds a child to the exception.
58
     *
59
     * @param ValidationException $exception
60
     *
61
     * @return self
62
     */
63 153
    public function addChild(ValidationException $exception): self
64
    {
65 153
        $this->exceptions[spl_object_hash($exception)] = $exception;
66
67 153
        return $this;
68
    }
69
70
    /**
71
     * Adds children to the exception.
72
     *
73
     * @param ValidationException[] $exceptions
74
     *
75
     * @return self
76
     */
77 151
    public function addChildren(array $exceptions): self
78
    {
79 151
        foreach ($exceptions as $exception) {
80 151
            $this->addChild($exception);
81
        }
82
83 151
        return $this;
84
    }
85
86
    /**
87
     * @return SplObjectStorage
88
     */
89 140
    public function getIterator(): SplObjectStorage
90
    {
91 140
        $childrenExceptions = new SplObjectStorage();
92 140
        $recursiveIteratorIterator = $this->getRecursiveIterator();
93
94 140
        $lastDepth = 0;
95 140
        $lastDepthOriginal = 0;
96 140
        $knownDepths = [];
97 140
        foreach ($recursiveIteratorIterator as $childException) {
98 139
            if ($this->isOmissible($childException)) {
99 8
                continue;
100
            }
101
102 139
            $currentDepth = $lastDepth;
103 139
            $currentDepthOriginal = $recursiveIteratorIterator->getDepth() + 1;
104
105 139
            if (isset($knownDepths[$currentDepthOriginal])) {
106 9
                $currentDepth = $knownDepths[$currentDepthOriginal];
107 139
            } elseif ($currentDepthOriginal > $lastDepthOriginal) {
108 139
                ++$currentDepth;
109
            }
110
111 139
            if (!isset($knownDepths[$currentDepthOriginal])) {
112 139
                $knownDepths[$currentDepthOriginal] = $currentDepth;
113
            }
114
115 139
            $lastDepth = $currentDepth;
116 139
            $lastDepthOriginal = $currentDepthOriginal;
117
118 139
            $childrenExceptions->attach($childException, $currentDepth);
119
        }
120
121 140
        return $childrenExceptions;
122
    }
123
124
    /**
125
     * Returns a key->value array with all the messages of the exception.
126
     *
127
     * In this array the "keys" are the ids of the exceptions (defined name or
128
     * name of the rule) and the values are the message.
129
     *
130
     * Once templates are passed it overwrites the templates of the given
131
     * messages.
132
     *
133
     * @param array $templates
134
     *
135
     * @return array
136
     */
137 8
    public function getMessages(array $templates = []): array
138
    {
139 8
        $messages = [$this->getId() => $this->renderMessage($this, $templates)];
140 8
        foreach ($this->getChildren() as $exception) {
141 8
            $id = $exception->getId();
142 8
            if (!$exception instanceof self) {
143 8
                $messages[$id] = $this->renderMessage(
144 8
                    $exception,
145 8
                    $this->findTemplates($templates, $this->getId())
146
                );
147 8
                continue;
148
            }
149
150 5
            $messages[$id] = $exception->getMessages($this->findTemplates($templates, $id, $this->getId()));
151 5
            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

151
            if (count(/** @scrutinizer ignore-type */ $messages[$id]) > 1) {
Loading history...
152 2
                continue;
153
            }
154
155 5
            $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

155
            $messages[$id] = current(/** @scrutinizer ignore-type */ $messages[$exception->getId()]);
Loading history...
156
        }
157
158 8
        if (count($messages) > 1) {
159 8
            unset($messages[$this->getId()]);
160
        }
161
162 8
        return $messages;
163
    }
164
165
    /**
166
     * Returns a string with all the messages of the exception.
167
     *
168
     * @return string
169
     */
170 140
    public function getFullMessage(): string
171
    {
172 140
        $messages = [];
173 140
        $leveler = 1;
174
175 140
        if (!$this->isOmissible($this)) {
176 10
            $leveler = 0;
177 10
            $messages[] = sprintf('- %s', $this->getMessage());
178
        }
179
180 140
        $exceptions = $this->getIterator();
181
        /** @var ValidationException $exception */
182 140
        foreach ($exceptions as $exception) {
183 139
            $messages[] = sprintf(
184 139
                '%s- %s',
185 139
                str_repeat(' ', (int) ($exceptions[$exception] - $leveler) * 2),
186 139
                $exception->getMessage()
187
            );
188
        }
189
190 140
        return implode(PHP_EOL, $messages);
191
    }
192
193 140
    private function getRecursiveIterator(): RecursiveIteratorIterator
194
    {
195 140
        return new RecursiveIteratorIterator(
196 140
            new RecursiveExceptionIterator($this),
197 140
            RecursiveIteratorIterator::SELF_FIRST
198
        );
199
    }
200
201 140
    private function isOmissible(Exception $exception): bool
202
    {
203 140
        if (!$exception instanceof self) {
204 132
            return false;
205
        }
206
207 140
        if (1 !== count($exception->getChildren())) {
208 19
            return false;
209
        }
210
211
        /** @var ValidationException $childException */
212 136
        $childException = current($exception->getChildren());
213 136
        if ($childException->getMessage() === $exception->getMessage()) {
214 3
            return true;
215
        }
216
217 135
        if ($exception->hasCustomTemplate()) {
218
            return $childException->hasCustomTemplate();
219
        }
220
221 135
        return !$childException instanceof NonOmissibleException;
222
    }
223
224 8
    private function renderMessage(ValidationException $exception, array $templates): string
225
    {
226 8
        if (isset($templates[$exception->getId()])) {
227 2
            $exception->updateTemplate($templates[$exception->getId()]);
228
        }
229
230 8
        return $exception->getMessage();
231
    }
232
233 8
    private function findTemplates(array $templates, ...$ids): array
234
    {
235 8
        while (count($ids) > 0) {
236 8
            $id = array_shift($ids);
237 8
            if (isset($templates[$id]) && is_array($templates[$id])) {
238 1
                $templates = $templates[$id];
239
            }
240
        }
241
242 8
        return $templates;
243
    }
244
}
245