ReplaceMutation::createEventGenerator()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 7
nc 4
nop 2
dl 0
loc 13
ccs 0
cts 8
cp 0
crap 20
rs 10
c 1
b 0
f 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\JSON\Path\Processor\Mutator;
6
7
use Generator;
8
use Iterator;
9
use Remorhaz\JSON\Data\Event\AfterElementEventInterface;
10
use Remorhaz\JSON\Data\Event\AfterPropertyEventInterface;
11
use Remorhaz\JSON\Data\Event\BeforeArrayEventInterface;
12
use Remorhaz\JSON\Data\Event\BeforeElementEventInterface;
13
use Remorhaz\JSON\Data\Event\BeforeObjectEventInterface;
14
use Remorhaz\JSON\Data\Event\BeforePropertyEventInterface;
15
use Remorhaz\JSON\Data\Event\EventInterface;
16
use Remorhaz\JSON\Data\Event\ScalarEventInterface;
17
use Remorhaz\JSON\Data\Path\PathInterface;
18
use Remorhaz\JSON\Data\Value\NodeValueInterface;
19
use Remorhaz\JSON\Data\Walker\MutationInterface;
20
use Remorhaz\JSON\Data\Walker\ValueWalkerInterface;
21
22
use function array_reverse;
23
use function count;
24
25
final class ReplaceMutation implements MutationInterface
26
{
27
28
    private $newNode;
29
30
    private $paths;
31
32
    public function __construct(NodeValueInterface $newNode, PathInterface ...$paths)
33
    {
34
        $this->newNode = $newNode;
35
        $this->paths = $this->getNonNestedPaths(...$paths);
36
    }
37
38
    private function getNonNestedPaths(PathInterface ...$paths): array
39
    {
40
        foreach ($this->createPathPairIterator(...$paths) as $pathPair) {
41
            [$parentPath, $nestedPath] = $pathPair;
42
            if ($parentPath->contains($nestedPath)) {
43
                throw new Exception\ReplaceAtNestedPathsException($parentPath, $nestedPath);
44
            }
45
        }
46
47
        return $paths;
48
    }
49
50
    /**
51
     * @param PathInterface ...$paths
52
     * @return Generator|PathInterface[][]
53
     */
54
    private function createPathPairIterator(PathInterface ...$paths): Generator
55
    {
56
        $pathsCount = count($paths);
57
        for ($i = 0; $i < $pathsCount; $i++) {
58
            for ($j = $i + 1; $j < $pathsCount; $j++) {
59
                $pathPair = [$paths[$i], $paths[$j]];
60
                yield $pathPair;
61
                yield array_reverse($pathPair);
62
            }
63
        }
64
    }
65
66
    public function __invoke(EventInterface $event, ValueWalkerInterface $valueWalker): Iterator
67
    {
68
        return $this->createEventGenerator($event, $valueWalker);
69
    }
70
71
    public function reset(): void
72
    {
73
    }
74
75
    private function createEventGenerator(EventInterface $event, ValueWalkerInterface $valueWalker): Generator
76
    {
77
        foreach ($this->paths as $path) {
78
            if ($path->equals($event->getPath())) {
79
                yield from $this->createReplaceEventGenerator($event, $valueWalker);
80
81
                return;
82
            }
83
            if ($path->contains($event->getPath())) {
84
                return;
85
            }
86
        }
87
        yield $event;
88
    }
89
90
    private function createReplaceEventGenerator(EventInterface $event, ValueWalkerInterface $valueWalker): Generator
91
    {
92
        switch (true) {
93
            case $event instanceof BeforeElementEventInterface:
94
            case $event instanceof BeforePropertyEventInterface:
95
            case $event instanceof AfterElementEventInterface:
96
            case $event instanceof AfterPropertyEventInterface:
97
                yield $event;
98
                break;
99
100
            case $event instanceof ScalarEventInterface:
101
            case $event instanceof BeforeArrayEventInterface:
102
            case $event instanceof BeforeObjectEventInterface:
103
                yield from $valueWalker
104
                    ->createEventIterator($this->newNode, $event->getPath());
105
                break;
106
        }
107
    }
108
}
109