BlockSerializer   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 296
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 32
lcom 2
cbo 6
dl 0
loc 296
ccs 96
cts 96
cp 1
rs 9.84
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A serialize() 0 6 1
A addBlock() 0 17 5
A getSerializedBlocks() 0 4 1
A getBlocksWithStart() 0 4 1
A getBlocksWithEnd() 0 4 1
A clearBlocks() 0 8 1
A clearBlocksWithStart() 0 6 1
A clearBlocksWithEnd() 0 6 1
A get() 0 8 1
A unserializeBlocks() 0 6 1
A unserializeBlocksWithStart() 0 6 1
A unserializeBlocksWithEnd() 0 6 1
A readProperty() 0 6 1
A reset() 0 4 1
A serializeProcedure() 0 24 4
A serializeIfExpression() 0 25 5
A allocateIndex() 0 6 1
A serializeAndExpression() 0 17 2
A serializeOrExpression() 0 17 2
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\Blocks\AndExpressionInterface;
22
use Limoncello\Validation\Contracts\Blocks\ExecutionBlockInterface;
23
use Limoncello\Validation\Contracts\Blocks\IfExpressionInterface;
24
use Limoncello\Validation\Contracts\Blocks\OrExpressionInterface;
25
use Limoncello\Validation\Contracts\Blocks\ProcedureBlockInterface;
26
use Limoncello\Validation\Contracts\Execution\BlockSerializerInterface;
27
use Limoncello\Validation\Exceptions\UnknownExecutionBlockType;
28
use function array_key_exists;
29
use function assert;
30
use function count;
31
32
/**
33
 * @package Limoncello\Validation
34
 */
35
final class BlockSerializer implements BlockSerializerInterface
36
{
37
    /**
38
     * Index of the first block.
39
     */
40
    public const FIRST_BLOCK_INDEX = 0;
41
42
    /**
43
     * @var int
44
     */
45
    private $currentBlockIndex = 0;
46
47
    /**
48
     * @var array
49
     */
50
    private $serializedBlocks = [];
51
52
    /**
53
     * @var int[]
54
     */
55
    private $blocksWithStart = [];
56
57
    /**
58
     * @var int[]
59
     */
60
    private $blocksWithEnd = [];
61
62
    /**
63
     * @inheritdoc
64
     */
65 13
    public function serialize(ExecutionBlockInterface $block): BlockSerializerInterface
66
    {
67 13
        $this->reset()->addBlock($block);
68
69 13
        return $this;
70
    }
71
72
    /**
73
     * @inheritdoc
74
     *
75
     * @SuppressWarnings(PHPMD.ElseExpression)
76
     */
77 26
    public function addBlock(ExecutionBlockInterface $block): int
78
    {
79 26
        if ($block instanceof ProcedureBlockInterface) {
80 25
            $index = $this->serializeProcedure($block);
81 15
        } elseif ($block instanceof IfExpressionInterface) {
82 8
            $index = $this->serializeIfExpression($block);
83 14
        } elseif ($block instanceof AndExpressionInterface) {
84 12
            $index = $this->serializeAndExpression($block);
85 6
        } elseif ($block instanceof OrExpressionInterface) {
86 5
            $index = $this->serializeOrExpression($block);
87
        } else {
88
            // unknown execution block type
89 1
            throw new UnknownExecutionBlockType();
90
        }
91
92 25
        return $index;
93
    }
94
95
    /**
96
     * @return array
97
     */
98 25
    public function getSerializedBlocks(): array
99
    {
100 25
        return $this->serializedBlocks;
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106 25
    public function getBlocksWithStart(): array
107
    {
108 25
        return $this->blocksWithStart;
109
    }
110
111
    /**
112
     * @inheritdoc
113
     */
114 25
    public function getBlocksWithEnd(): array
115
    {
116 25
        return $this->blocksWithEnd;
117
    }
118
119
    /**
120
     * @inheritdoc
121
     */
122 13
    public function clearBlocks(): BlockSerializerInterface
123
    {
124 13
        $this->currentBlockIndex = 0;
125 13
        $this->serializedBlocks  = [];
126
127
128 13
        return $this;
129
    }
130
131
    /**
132
     * @inheritdoc
133
     */
134 13
    public function clearBlocksWithStart(): BlockSerializerInterface
135
    {
136 13
        $this->blocksWithStart = [];
137
138 13
        return $this;
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144 13
    public function clearBlocksWithEnd(): BlockSerializerInterface
145
    {
146 13
        $this->blocksWithEnd = [];
147
148 13
        return $this;
149
    }
150
151
    /**
152
     * @inheritdoc
153
     */
154 25
    public function get(): array
155
    {
156
        return [
157 25
            static::SERIALIZATION_BLOCKS            => $this->getSerializedBlocks(),
158 25
            static::SERIALIZATION_BLOCKS_WITH_START => $this->getBlocksWithStart(),
159 25
            static::SERIALIZATION_BLOCKS_WITH_END   => $this->getBlocksWithEnd(),
160
        ];
161
    }
162
163
    /**
164
     * @inheritdoc
165
     */
166 21
    public static function unserializeBlocks(array $serialized): array
167
    {
168 21
        assert(count($serialized) === 3); // blocks, starts, ends
169
170 21
        return static::readProperty(static::SERIALIZATION_BLOCKS, $serialized);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockSerializer 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...
171
    }
172
173
    /**
174
     * @inheritdoc
175
     */
176 21
    public static function unserializeBlocksWithStart(array $serialized): array
177
    {
178 21
        assert(count($serialized) === 3); // blocks, starts, ends
179
180 21
        return static::readProperty(static::SERIALIZATION_BLOCKS_WITH_START, $serialized);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockSerializer 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...
181
    }
182
183
    /**
184
     * @inheritdoc
185
     */
186 21
    public static function unserializeBlocksWithEnd(array $serialized): array
187
    {
188 21
        assert(count($serialized) === 3); // blocks, starts, ends
189
190 21
        return static::readProperty(static::SERIALIZATION_BLOCKS_WITH_END, $serialized);
0 ignored issues
show
Comprehensibility introduced by
Since Limoncello\Validation\Execution\BlockSerializer 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
    }
192
193
    /**
194
     * @param int   $key
195
     * @param array $properties
196
     *
197
     * @return mixed
198
     */
199 21
    private static function readProperty(int $key, array $properties)
200
    {
201 21
        assert(array_key_exists($key, $properties));
202
203 21
        return $properties[$key];
204
    }
205
206
    /**
207
     * @return BlockSerializerInterface
208
     */
209 13
    private function reset(): BlockSerializerInterface
210
    {
211 13
        return $this->clearBlocks()->clearBlocksWithStart()->clearBlocksWithEnd();
212
    }
213
214
    /**
215
     * @param ProcedureBlockInterface $procedure
216
     *
217
     * @return int
218
     */
219 25
    private function serializeProcedure(ProcedureBlockInterface $procedure): int
220
    {
221 25
        $index = $this->allocateIndex();
222
223
        $serialized = [
224 25
            static::TYPE                       => static::TYPE__PROCEDURE,
225 25
            static::PROCEDURE_EXECUTE_CALLABLE => $procedure->getExecuteCallable(),
226
        ];
227 25
        if ($procedure->getStartCallable() !== null) {
228 6
            $serialized[static::PROCEDURE_START_CALLABLE] = $procedure->getStartCallable();
229 6
            $this->blocksWithStart[]                      = $index;
230
        }
231 25
        if ($procedure->getEndCallable() !== null) {
232 7
            $serialized[static::PROCEDURE_END_CALLABLE] = $procedure->getEndCallable();
233 7
            $this->blocksWithEnd[]                      = $index;
234
        }
235 25
        if (empty($procedure->getProperties()) === false) {
236 25
            $serialized[static::PROPERTIES] = $procedure->getProperties();
237
        }
238
239 25
        $this->serializedBlocks[$index] = $serialized;
240
241 25
        return $index;
242
    }
243
244
    /**
245
     * @param IfExpressionInterface $ifExpression
246
     *
247
     * @return int
248
     */
249 8
    private function serializeIfExpression(IfExpressionInterface $ifExpression): int
250
    {
251 8
        $index = $this->allocateIndex();
252
253
        $serialized = [
254 8
            static::TYPE                             => static::TYPE__IF_EXPRESSION,
255 8
            static::IF_EXPRESSION_CONDITION_CALLABLE => $ifExpression->getConditionCallable(),
256
        ];
257
258 8
        assert($ifExpression->getOnTrue() !== null || $ifExpression->getOnFalse() !== null);
259
260 8
        if ($ifExpression->getOnTrue() !== null) {
261 8
            $serialized[static::IF_EXPRESSION_ON_TRUE_BLOCK] = $this->addBlock($ifExpression->getOnTrue());
262
        }
263 8
        if ($ifExpression->getOnFalse() !== null) {
264 8
            $serialized[static::IF_EXPRESSION_ON_FALSE_BLOCK] = $this->addBlock($ifExpression->getOnFalse());
265
        }
266 8
        if (empty($ifExpression->getProperties()) === false) {
267 8
            $serialized[static::PROPERTIES] = $ifExpression->getProperties();
268
        }
269
270 8
        $this->serializedBlocks[$index] = $serialized;
271
272 8
        return $index;
273
    }
274
275
    /**
276
     * @param AndExpressionInterface $andExpression
277
     *
278
     * @return int
279
     */
280 12
    private function serializeAndExpression(AndExpressionInterface $andExpression): int
281
    {
282 12
        $index = $this->allocateIndex();
283
284
        $serialized = [
285 12
            static::TYPE                     => static::TYPE__AND_EXPRESSION,
286 12
            static::AND_EXPRESSION_PRIMARY   => $this->addBlock($andExpression->getPrimary()),
287 12
            static::AND_EXPRESSION_SECONDARY => $this->addBlock($andExpression->getSecondary()),
288
        ];
289 12
        if (empty($andExpression->getProperties()) === false) {
290 12
            $serialized[static::PROPERTIES] = $andExpression->getProperties();
291
        }
292
293 12
        $this->serializedBlocks[$index] = $serialized;
294
295 12
        return $index;
296
    }
297
298
    /**
299
     * @param OrExpressionInterface $orExpression
300
     *
301
     * @return int
302
     */
303 5
    private function serializeOrExpression(OrExpressionInterface $orExpression): int
304
    {
305 5
        $index = $this->allocateIndex();
306
307
        $serialized = [
308 5
            static::TYPE                    => static::TYPE__OR_EXPRESSION,
309 5
            static::OR_EXPRESSION_PRIMARY   => $this->addBlock($orExpression->getPrimary()),
310 5
            static::OR_EXPRESSION_SECONDARY => $this->addBlock($orExpression->getSecondary()),
311
        ];
312 5
        if (empty($orExpression->getProperties()) === false) {
313 5
            $serialized[static::PROPERTIES] = $orExpression->getProperties();
314
        }
315
316 5
        $this->serializedBlocks[$index] = $serialized;
317
318 5
        return $index;
319
    }
320
321
    /**
322
     * @return int
323
     */
324 25
    private function allocateIndex(): int
325
    {
326 25
        $index = $this->currentBlockIndex++;
327
328 25
        return $index;
329
    }
330
}
331