Passed
Push — master ( 31414b...55792b )
by Edward
04:28
created

ReplaceMutation::getNonNestedPaths()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 5
c 1
b 0
f 1
nc 3
nop 1
dl 0
loc 10
ccs 0
cts 6
cp 0
crap 12
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Path\Processor\Mutator;
5
6
use Generator;
7
use Iterator;
8
use Remorhaz\JSON\Data\Event\AfterElementEventInterface;
9
use Remorhaz\JSON\Data\Event\AfterPropertyEventInterface;
10
use Remorhaz\JSON\Data\Event\BeforeArrayEventInterface;
11
use Remorhaz\JSON\Data\Event\BeforeElementEventInterface;
12
use Remorhaz\JSON\Data\Event\BeforeObjectEventInterface;
13
use Remorhaz\JSON\Data\Event\BeforePropertyEventInterface;
14
use Remorhaz\JSON\Data\Event\EventInterface;
15
use Remorhaz\JSON\Data\Event\ScalarEventInterface;
16
use Remorhaz\JSON\Data\Event\ValueWalkerInterface;
17
use Remorhaz\JSON\Data\Path\PathInterface;
18
use Remorhaz\JSON\Data\Value\NodeValueInterface;
19
use function array_reverse;
20
use function count;
21
22
final class ReplaceMutation implements MutationInterface
23
{
24
25
    private $valueWalker;
26
27
    private $newNode;
28
29
    private $paths;
30
31
    public function __construct(ValueWalkerInterface $valueWalker, NodeValueInterface $newNode, PathInterface ...$paths)
32
    {
33
        $this->valueWalker = $valueWalker;
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): Iterator
67
    {
68
        return $this->createEventGenerator($event);
69
    }
70
71
    private function createEventGenerator(EventInterface $event): Generator
72
    {
73
        foreach ($this->paths as $path) {
74
            if ($path->equals($event->getPath())) {
75
                yield from $this->createReplaceEventGenerator($event);
76
                return;
77
            }
78
            if ($path->contains($event->getPath())) {
79
                return;
80
            }
81
        }
82
        yield $event;
83
    }
84
85
    private function createReplaceEventGenerator(EventInterface $event): Generator
86
    {
87
        switch (true) {
88
            case $event instanceof BeforeElementEventInterface:
89
            case $event instanceof BeforePropertyEventInterface:
90
            case $event instanceof AfterElementEventInterface:
91
            case $event instanceof AfterPropertyEventInterface:
92
                yield $event;
93
                break;
94
95
            case $event instanceof ScalarEventInterface:
96
            case $event instanceof BeforeArrayEventInterface:
97
            case $event instanceof BeforeObjectEventInterface:
98
                yield from $this
99
                    ->valueWalker
100
                    ->createEventIterator($this->newNode, $event->getPath());
101
                break;
102
        }
103
    }
104
}
105