BlockInterpreter   B
last analyzed

Complexity

Total Complexity 50

Size/Duplication

Total Lines 530
Duplicated Lines 24.34 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 129
loc 530
c 0
b 0
f 0
wmc 50
lcom 1
cbo 6
rs 8.4
ccs 173
cts 173
cp 1

20 Methods

Rating   Name   Duplication   Size   Complexity  
A execute() 0 16 3
A executeStarts() 20 20 3
A executeEnds() 20 20 3
A executeBlock() 0 24 2
A executeBlockImpl() 0 30 5
A executeProcedureBlock() 0 18 1
A executeIfBlock() 0 24 2
A executeAndBlock() 22 22 2
A executeOrBlock() 23 23 2
A getBlocks() 0 7 1
A getBlocksWithStart() 12 12 2
A getBlocksWithEnd() 12 12 2
A getBlockType() 0 8 1
A captureSuccessfulBlockResultIfEnabled() 0 14 3
A executeProcedureStart() 10 10 1
A executeProcedureEnd() 10 10 1
A addBlockErrors() 0 17 2
A debugCheckLooksLikeBlocksArray() 0 13 5
A debugCheckBlocksExist() 0 12 4
A debugHasKnownBlockType() 0 16 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BlockInterpreter 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 BlockInterpreter, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace Limoncello\Validation\Execution;
4
5
/**
6
 * Copyright 2015-2020 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Limoncello\Validation\Contracts\Captures\CaptureAggregatorInterface;
22
use Limoncello\Validation\Contracts\Errors\ErrorAggregatorInterface;
23
use Limoncello\Validation\Contracts\Execution\ContextInterface;
24
use Limoncello\Validation\Contracts\Execution\ContextStorageInterface;
25
use Limoncello\Validation\Errors\Error;
26
use Limoncello\Validation\Rules\BaseRule;
27
use function array_key_exists;
28
use function assert;
29
use function call_user_func;
30
use function is_array;
31
use function is_bool;
32
use function is_callable;
33
use function is_int;
34
use function is_iterable;
35
36
/**
37
 * @package Limoncello\Validation
38
 *
39
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
40
 */
41
final class BlockInterpreter
42
{
43
    /**
44
     * @param mixed                      $input
45
     * @param array                      $serializedBlocks
46
     * @param ContextStorageInterface    $context
47
     * @param CaptureAggregatorInterface $captures
48
     * @param ErrorAggregatorInterface   $errors
49
     *
50
     * @return bool
51
     *
52
     * @SuppressWarnings(PHPMD.StaticAccess)
53
     */
54 9
    public static function execute(
55
        $input,
56
        array $serializedBlocks,
57
        ContextStorageInterface $context,
58
        CaptureAggregatorInterface $captures,
59
        ErrorAggregatorInterface $errors
60
    ): bool {
61 9
        $blockIndex = BlockSerializer::FIRST_BLOCK_INDEX;
62
63 9
        $blocks   = static::getBlocks($serializedBlocks);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
64 9
        $startsOk = static::executeStarts(static::getBlocksWithStart($serializedBlocks), $blocks, $context, $errors);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
65 9
        $blockOk  = static::executeBlock($input, $blockIndex, $blocks, $context, $captures, $errors);
66 9
        $endsOk   = static::executeEnds(static::getBlocksWithEnd($serializedBlocks), $blocks, $context, $errors);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
67
68 9
        return $startsOk && $blockOk && $endsOk;
69
    }
70
71
    /**
72
     * @param iterable|int[]           $indexes
73
     * @param array                    $blocks
74
     * @param ContextStorageInterface  $context
75
     * @param ErrorAggregatorInterface $errors
76
     *
77
     * @return bool
78
     *
79
     * @SuppressWarnings(PHPMD.StaticAccess)
80
     */
81 21 View Code Duplication
    public static function executeStarts(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
82
        iterable $indexes,
83
        array $blocks,
84
        ContextStorageInterface $context,
85
        ErrorAggregatorInterface $errors
86
    ): bool {
87 21
        $allOk = true;
88
89 21
        foreach ($indexes as $index) {
90 5
            $context->setCurrentBlockId($index);
91 5
            $block      = $blocks[$index];
92 5
            $errorsInfo = static::executeProcedureStart($block, $context);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
93 5
            if (empty($errorsInfo) === false) {
94 2
                static::addBlockErrors($errorsInfo, $context, $errors);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
Documentation introduced by
$errorsInfo is of type array, but the function expects a object<Limoncello\Validation\Execution\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
95 5
                $allOk = false;
96
            }
97
        }
98
99 21
        return $allOk;
100
    }
101
102
    /**
103
     * @param iterable|int[]           $indexes
104
     * @param array                    $blocks
105
     * @param ContextStorageInterface  $context
106
     * @param ErrorAggregatorInterface $errors
107
     *
108
     * @return bool
109
     *
110
     * @SuppressWarnings(PHPMD.StaticAccess)
111
     */
112 21 View Code Duplication
    public static function executeEnds(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
113
        iterable $indexes,
114
        array $blocks,
115
        ContextStorageInterface $context,
116
        ErrorAggregatorInterface $errors
117
    ): bool {
118 21
        $allOk = true;
119
120 21
        foreach ($indexes as $index) {
121 6
            $context->setCurrentBlockId($index);
122 6
            $block      = $blocks[$index];
123 6
            $errorsInfo = static::executeProcedureEnd($block, $context);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
124 6
            if (empty($errorsInfo) === false) {
125 3
                static::addBlockErrors($errorsInfo, $context, $errors);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
Documentation introduced by
$errorsInfo is of type array, but the function expects a object<Limoncello\Validation\Execution\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
126 6
                $allOk = false;
127
            }
128
        }
129
130 21
        return $allOk;
131
    }
132
133
    /**
134
     * @param mixed                      $input
135
     * @param int                        $blockIndex
136
     * @param array                      $blocks
137
     * @param ContextStorageInterface    $context
138
     * @param CaptureAggregatorInterface $captures
139
     * @param ErrorAggregatorInterface   $errors
140
     *
141
     * @return bool
142
     *
143
     * @SuppressWarnings(PHPMD.StaticAccess)
144
     */
145 21
    public static function executeBlock(
146
        $input,
147
        int $blockIndex,
148
        array $blocks,
149
        ContextStorageInterface $context,
150
        CaptureAggregatorInterface $captures,
151
        ErrorAggregatorInterface $errors
152
    ): bool {
153 21
        $result = static::executeBlockImpl(
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
154 21
            $input,
155 21
            $blockIndex,
156 21
            $blocks,
157 21
            $context,
158 21
            $captures
159
        );
160 21
        if (BlockReplies::isResultSuccessful($result) === false) {
161 14
            $errorsInfo = BlockReplies::extractResultErrorsInfo($result);
162 14
            static::addBlockErrors($errorsInfo, $context, $errors);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
Documentation introduced by
$errorsInfo is of type array, but the function expects a object<Limoncello\Validation\Execution\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
163
164 14
            return false;
165
        }
166
167 19
        return true;
168
    }
169
170
    /**
171
     * @param mixed                      $input
172
     * @param int                        $blockIndex
173
     * @param array                      $blocks
174
     * @param ContextStorageInterface    $context
175
     * @param CaptureAggregatorInterface $captures
176
     *
177
     * @return array
178
     *
179
     * @SuppressWarnings(PHPMD.StaticAccess)
180
     */
181 21
    private static function executeBlockImpl(
182
        $input,
183
        int $blockIndex,
184
        array $blocks,
185
        ContextStorageInterface $context,
186
        CaptureAggregatorInterface $captures
187
    ): array {
188 21
        assert(array_key_exists($blockIndex, $blocks));
189
190 21
        $blockType = static::getBlockType($blocks[$blockIndex]);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
191 21
        $context->setCurrentBlockId($blockIndex);
192
        switch ($blockType) {
193 21
            case BlockSerializer::TYPE__PROCEDURE:
194 21
                $result = static::executeProcedureBlock($input, $blockIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
195 21
                break;
196 11
            case BlockSerializer::TYPE__IF_EXPRESSION:
197 7
                $result = static::executeIfBlock($input, $blockIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
198 7
                break;
199 11
            case BlockSerializer::TYPE__AND_EXPRESSION:
200 11
                $result = static::executeAndBlock($input, $blockIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
201 11
                break;
202 4
            case BlockSerializer::TYPE__OR_EXPRESSION:
203
            default:
204 4
                assert($blockType === BlockSerializer::TYPE__OR_EXPRESSION);
205 4
                $result = static::executeOrBlock($input, $blockIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
206 4
                break;
207
        }
208
209 21
        return $result;
210
    }
211
212
    /**
213
     * @param mixed                      $input
214
     * @param int                        $blockIndex
215
     * @param array                      $blocks
216
     * @param ContextStorageInterface    $context
217
     * @param CaptureAggregatorInterface $captures
218
     *
219
     * @return array
220
     *
221
     * @SuppressWarnings(PHPMD.StaticAccess)
222
     */
223 21
    private static function executeProcedureBlock(
224
        $input,
225
        int $blockIndex,
226
        array $blocks,
227
        ContextStorageInterface $context,
228
        CaptureAggregatorInterface $captures
229
    ): array {
230 21
        $block = $blocks[$blockIndex];
231 21
        assert(static::getBlockType($block) === BlockSerializer::TYPE__PROCEDURE);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
232
233 21
        $procedure = $block[BlockSerializer::PROCEDURE_EXECUTE_CALLABLE];
234 21
        assert(is_callable($procedure));
235 21
        $result = call_user_func($procedure, $input, $context);
236
237 21
        static::captureSuccessfulBlockResultIfEnabled($result, $block, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
238
239 21
        return $result;
240
    }
241
242
    /**
243
     * @param mixed                      $input
244
     * @param int                        $blockIndex
245
     * @param array                      $blocks
246
     * @param ContextStorageInterface    $context
247
     * @param CaptureAggregatorInterface $captures
248
     *
249
     * @return array
250
     *
251
     * @SuppressWarnings(PHPMD.StaticAccess)
252
     */
253 7
    private static function executeIfBlock(
254
        $input,
255
        int $blockIndex,
256
        array $blocks,
257
        ContextStorageInterface $context,
258
        CaptureAggregatorInterface $captures
259
    ): array {
260 7
        $block = $blocks[$blockIndex];
261 7
        assert(static::getBlockType($block) === BlockSerializer::TYPE__IF_EXPRESSION);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
262
263 7
        $conditionCallable = $block[BlockSerializer::IF_EXPRESSION_CONDITION_CALLABLE];
264 7
        assert(is_callable($conditionCallable));
265 7
        $conditionResult = call_user_func($conditionCallable, $input, $context);
266 7
        assert(is_bool($conditionResult));
267
268 7
        $index = $block[$conditionResult === true ?
269 7
            BlockSerializer::IF_EXPRESSION_ON_TRUE_BLOCK : BlockSerializer::IF_EXPRESSION_ON_FALSE_BLOCK];
270
271 7
        $result = static::executeBlockImpl($input, $index, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
272
273 7
        static::captureSuccessfulBlockResultIfEnabled($result, $block, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
274
275 7
        return $result;
276
    }
277
278
    /**
279
     * @param mixed                      $input
280
     * @param int                        $blockIndex
281
     * @param array                      $blocks
282
     * @param ContextStorageInterface    $context
283
     * @param CaptureAggregatorInterface $captures
284
     *
285
     * @return array
286
     *
287
     * @SuppressWarnings(PHPMD.StaticAccess)
288
     */
289 11 View Code Duplication
    private static function executeAndBlock(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
290
        $input,
291
        int $blockIndex,
292
        array $blocks,
293
        ContextStorageInterface $context,
294
        CaptureAggregatorInterface $captures
295
    ): array {
296 11
        $block = $blocks[$blockIndex];
297 11
        assert(static::getBlockType($block) === BlockSerializer::TYPE__AND_EXPRESSION);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
298
299 11
        $primaryIndex = $block[BlockSerializer::AND_EXPRESSION_PRIMARY];
300 11
        $result       = static::executeBlockImpl($input, $primaryIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
301 11
        if (BlockReplies::isResultSuccessful($result) === true) {
302 11
            $nextInput      = BlockReplies::extractResultOutput($result);
303 11
            $secondaryIndex = $block[BlockSerializer::AND_EXPRESSION_SECONDARY];
304 11
            $result         = static::executeBlockImpl($nextInput, $secondaryIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
305
        }
306
307 11
        static::captureSuccessfulBlockResultIfEnabled($result, $block, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
308
309 11
        return $result;
310
    }
311
312
    /**
313
     * @param mixed                      $input
314
     * @param int                        $blockIndex
315
     * @param array                      $blocks
316
     * @param ContextStorageInterface    $context
317
     * @param CaptureAggregatorInterface $captures
318
     *
319
     * @return array
320
     *
321
     * @SuppressWarnings(PHPMD.StaticAccess)
322
     * @SuppressWarnings(PHPMD.ElseExpression)
323
     */
324 4 View Code Duplication
    private static function executeOrBlock(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
325
        $input,
326
        int $blockIndex,
327
        array $blocks,
328
        ContextStorageInterface $context,
329
        CaptureAggregatorInterface $captures
330
    ): array {
331 4
        $block = $blocks[$blockIndex];
332 4
        assert(static::getBlockType($block) === BlockSerializer::TYPE__OR_EXPRESSION);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
333
334 4
        $primaryIndex      = $block[BlockSerializer::OR_EXPRESSION_PRIMARY];
335 4
        $resultFromPrimary = static::executeBlockImpl($input, $primaryIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
336 4
        if (BlockReplies::isResultSuccessful($resultFromPrimary) === true) {
337 4
            $result = $resultFromPrimary;
338
        } else {
339 4
            $secondaryIndex = $block[BlockSerializer::OR_EXPRESSION_SECONDARY];
340 4
            $result         = static::executeBlockImpl($input, $secondaryIndex, $blocks, $context, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
341
        }
342
343 4
        static::captureSuccessfulBlockResultIfEnabled($result, $block, $captures);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
344
345 4
        return $result;
346
    }
347
348
    /**
349
     * @param array $serializedBlocks
350
     *
351
     * @return array
352
     *
353
     * @SuppressWarnings(PHPMD.StaticAccess)
354
     */
355 9
    private static function getBlocks(array $serializedBlocks): array
356
    {
357 9
        $blocks = BlockSerializer::unserializeBlocks($serializedBlocks);
358 9
        assert(static::debugCheckLooksLikeBlocksArray($blocks));
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
Documentation introduced by
$blocks is of type array, but the function expects a object<Limoncello\Validation\Execution\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
359
360 9
        return $blocks;
361
    }
362
363
    /**
364
     * @param array $serializedBlocks
365
     *
366
     * @return array
367
     *
368
     * @SuppressWarnings(PHPMD.StaticAccess)
369
     */
370 9 View Code Duplication
    private static function getBlocksWithStart(array $serializedBlocks): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
371
    {
372 9
        $blocksWithStart = BlockSerializer::unserializeBlocksWithStart($serializedBlocks);
373
374
        // check result contain only block indexes and the blocks are procedures
375 9
        assert(
376 9
            is_array($blocks = static::getBlocks($serializedBlocks)) &&
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
377 9
            static::debugCheckBlocksExist($blocksWithStart, $blocks, BlockSerializer::TYPE__PROCEDURE)
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
378
        );
379
380 9
        return $blocksWithStart;
381
    }
382
383
    /**
384
     * @param array $serializedBlocks
385
     *
386
     * @return array
387
     *
388
     * @SuppressWarnings(PHPMD.StaticAccess)
389
     */
390 9 View Code Duplication
    private static function getBlocksWithEnd(array $serializedBlocks): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
391
    {
392 9
        $blocksWithEnd = BlockSerializer::unserializeBlocksWithEnd($serializedBlocks);
393
394
        // check result contain only block indexes and the blocks are procedures
395 9
        assert(
396 9
            is_array($blocks = static::getBlocks($serializedBlocks)) &&
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
397 9
            static::debugCheckBlocksExist($blocksWithEnd, $blocks, BlockSerializer::TYPE__PROCEDURE)
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
398
        );
399
400 9
        return $blocksWithEnd;
401
    }
402
403
    /**
404
     * @param array $block
405
     *
406
     * @return int
407
     *
408
     * @SuppressWarnings(PHPMD.StaticAccess)
409
     */
410 21
    private static function getBlockType(array $block): int
411
    {
412 21
        assert(static::debugHasKnownBlockType($block));
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
413
414 21
        $type = $block[BlockSerializer::TYPE];
415
416 21
        return $type;
417
    }
418
419
    /**
420
     * @param array                      $result
421
     * @param array                      $block
422
     * @param CaptureAggregatorInterface $captures
423
     *
424
     * @return void
425
     *
426
     * @SuppressWarnings(PHPMD.StaticAccess)
427
     */
428 21
    private static function captureSuccessfulBlockResultIfEnabled(
429
        array $result,
430
        array $block,
431
        CaptureAggregatorInterface $captures
432
    ): void {
433 21
        if (BlockReplies::isResultSuccessful($result) === true) {
434 19
            $isCaptureEnabled = $block[BlockSerializer::PROPERTIES][BaseRule::PROPERTY_IS_CAPTURE_ENABLED] ?? false;
435 19
            if ($isCaptureEnabled === true) {
436 18
                $name  = $block[BlockSerializer::PROPERTIES][BaseRule::PROPERTY_NAME];
437 18
                $value = BlockReplies::extractResultOutput($result);
438 18
                $captures->remember($name, $value);
439
            }
440
        }
441
    }
442
443
    /**
444
     * @param array            $procedureBlock
445
     * @param ContextInterface $context
446
     *
447
     * @return array
448
     *
449
     * @SuppressWarnings(PHPMD.StaticAccess)
450
     */
451 5 View Code Duplication
    private static function executeProcedureStart(array $procedureBlock, ContextInterface $context): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
452
    {
453 5
        assert(static::getBlockType($procedureBlock) === BlockSerializer::TYPE__PROCEDURE);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
454 5
        $callable = $procedureBlock[BlockSerializer::PROCEDURE_START_CALLABLE];
455 5
        assert(is_callable($callable) === true);
456 5
        $errors = call_user_func($callable, $context);
457 5
        assert(is_array($errors));
458
459 5
        return $errors;
460
    }
461
462
    /**
463
     * @param array            $procedureBlock
464
     * @param ContextInterface $context
465
     *
466
     * @return array
467
     *
468
     * @SuppressWarnings(PHPMD.StaticAccess)
469
     */
470 6 View Code Duplication
    private static function executeProcedureEnd(array $procedureBlock, ContextInterface $context): iterable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
471
    {
472 6
        assert(static::getBlockType($procedureBlock) === BlockSerializer::TYPE__PROCEDURE);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
473 6
        $callable = $procedureBlock[BlockSerializer::PROCEDURE_END_CALLABLE];
474 6
        assert(is_callable($callable) === true);
475 6
        $errors = call_user_func($callable, $context);
476 6
        assert(is_iterable($errors));
477
478 6
        return $errors;
479
    }
480
481
    /**
482
     * @param iterable                 $errorsInfo
483
     * @param ContextStorageInterface  $context
484
     * @param ErrorAggregatorInterface $errors
485
     *
486
     * @return void
487
     */
488 17
    private static function addBlockErrors(
489
        iterable $errorsInfo,
490
        ContextStorageInterface $context,
491
        ErrorAggregatorInterface $errors
492
    ): void {
493 17
        foreach ($errorsInfo as $errorInfo) {
494 17
            $index           = $errorInfo[BlockReplies::ERROR_INFO_BLOCK_INDEX];
495 17
            $value           = $errorInfo[BlockReplies::ERROR_INFO_VALUE];
496 17
            $errorCode       = $errorInfo[BlockReplies::ERROR_INFO_CODE];
497 17
            $messageTemplate = $errorInfo[BlockReplies::ERROR_INFO_MESSAGE_TEMPLATE];
498 17
            $messageParams   = $errorInfo[BlockReplies::ERROR_INFO_MESSAGE_PARAMETERS];
499
500 17
            $name = $context->setCurrentBlockId($index)->getProperties()->getProperty(BaseRule::PROPERTY_NAME);
501
502 17
            $errors->add(new Error($name, $value, $errorCode, $messageTemplate, $messageParams));
503
        }
504
    }
505
506
    /**
507
     * @param iterable $blocks
508
     *
509
     * @return bool
510
     *
511
     * @SuppressWarnings(PHPMD.StaticAccess)
512
     */
513 9
    private static function debugCheckLooksLikeBlocksArray(iterable $blocks): bool
514
    {
515 9
        $result = true;
516
517 9
        foreach ($blocks as $index => $block) {
518 9
            $result = $result &&
519 9
                is_int($index) === true &&
520 9
                is_array($block) === true &&
521 9
                static::debugHasKnownBlockType($block) === true;
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
522
        }
523
524 9
        return $result;
525
    }
526
527
    /**
528
     * @param iterable|int[] $blockIndexes
529
     * @param array          $blockList
530
     * @param int            $blockType
531
     *
532
     * @return bool
533
     *
534
     * @SuppressWarnings(PHPMD.StaticAccess)
535
     */
536 9
    private static function debugCheckBlocksExist(iterable $blockIndexes, array $blockList, int $blockType): bool
537
    {
538 9
        $result = true;
539
540 9
        foreach ($blockIndexes as $index) {
541 5
            $result = $result &&
542 5
                array_key_exists($index, $blockList) === true &&
543 5
                static::getBlockType($blockList[$index]) === $blockType;
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockInterpreter is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
544
        }
545
546 9
        return $result;
547
    }
548
549
    /**
550
     * @param array $block
551
     *
552
     * @return bool
553
     */
554 21
    private static function debugHasKnownBlockType(array $block): bool
555
    {
556 21
        $result = false;
557
558 21
        if (array_key_exists(BlockSerializer::TYPE, $block) === true) {
559 21
            $type = $block[BlockSerializer::TYPE];
560
561
            $result =
562 21
                $type === BlockSerializer::TYPE__PROCEDURE ||
563 21
                $type === BlockSerializer::TYPE__AND_EXPRESSION ||
564 21
                $type === BlockSerializer::TYPE__OR_EXPRESSION ||
565 21
                $type === BlockSerializer::TYPE__IF_EXPRESSION;
566
        }
567
568 21
        return $result;
569
    }
570
}
571