Passed
Push — master ( 531553...9683f3 )
by Edward
04:25
created

Processor::createDeleteMutation()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 9
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 15
ccs 10
cts 10
cp 1
crap 5
rs 9.6111
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Pointer\Processor;
5
6
use Remorhaz\JSON\Data\Export\EventDecoder;
7
use Remorhaz\JSON\Data\Export\ValueDecoder;
8
use Remorhaz\JSON\Data\Export\ValueDecoderInterface;
9
use Remorhaz\JSON\Data\Export\ValueEncoder;
10
use Remorhaz\JSON\Data\Export\ValueEncoderInterface;
11
use Remorhaz\JSON\Data\Value\ArrayValueInterface;
12
use Remorhaz\JSON\Data\Value\NodeValueInterface;
13
use Remorhaz\JSON\Data\Value\ObjectValueInterface;
14
use Remorhaz\JSON\Data\Walker\MutationInterface;
15
use Remorhaz\JSON\Data\Walker\ValueWalker;
16
use Remorhaz\JSON\Pointer\Locator\IndexReferenceInterface;
17
use Remorhaz\JSON\Pointer\Locator\NextIndexReferenceInterface;
18
use Remorhaz\JSON\Pointer\Locator\ReferenceInterface;
19
use Remorhaz\JSON\Pointer\Processor\Mutator\AppendElementMutation;
20
use Remorhaz\JSON\Pointer\Processor\Mutator\AppendPropertyMutation;
21
use Remorhaz\JSON\Pointer\Processor\Mutator\DeleteElementMutation;
22
use Remorhaz\JSON\Pointer\Processor\Mutator\DeletePropertyMutation;
23
use Remorhaz\JSON\Pointer\Processor\Mutator\InsertElementMutation;
24
use Remorhaz\JSON\Pointer\Processor\Mutator\Mutator;
25
use Remorhaz\JSON\Pointer\Processor\Mutator\MutatorInterface;
26
use Remorhaz\JSON\Pointer\Processor\Mutator\ReplaceMutation;
27
use Remorhaz\JSON\Pointer\Processor\Result\ExistingResult;
28
use Remorhaz\JSON\Pointer\Processor\Result\NonExistingResult;
29
use Remorhaz\JSON\Pointer\Processor\Result\ResultInterface;
30
use Remorhaz\JSON\Pointer\Query\QueryInterface;
31
use Remorhaz\JSON\Pointer\Query\QueryResultInterface;
32
33
final class Processor implements ProcessorInterface
34
{
35
36
    private $encoder;
37
38
    private $decoder;
39
40
    private $mutator;
41
42 16
    public static function create(): ProcessorInterface
43
    {
44 16
        $decoder = new ValueDecoder;
45
46 16
        return new self(
47 16
            new ValueEncoder($decoder),
48
            $decoder,
49 16
            new Mutator(
50 16
                new ValueWalker(),
51 16
                new EventDecoder(),
52
            ),
53
        );
54
    }
55
56 41
    public function __construct(
57
        ValueEncoderInterface $encoder,
58
        ValueDecoderInterface $decoder,
59
        MutatorInterface $mutator
60
    ) {
61 41
        $this->encoder = $encoder;
62 41
        $this->decoder = $decoder;
63 41
        $this->mutator = $mutator;
64 41
    }
65
66 5
    public function select(QueryInterface $query, NodeValueInterface $rootNode): ResultInterface
67
    {
68 5
        $queryResult = $query($rootNode);
69
70 5
        return $queryResult->hasSelection()
71 3
            ? new ExistingResult($this->encoder, $this->decoder, $queryResult->getSelection())
72 5
            : new NonExistingResult($query->getSource());
73
    }
74
75 11
    public function delete(QueryInterface $query, NodeValueInterface $rootNode): ResultInterface
76
    {
77 11
        $mutation = $this->createDeleteMutation($query($rootNode));
78
79 11
        return isset($mutation)
80 6
            ? $this->getMutationResult($query, $rootNode, $mutation)
81 11
            : new NonExistingResult($query->getSource());
82
    }
83
84 11
    private function createDeleteMutation(QueryResultInterface $queryResult): ?MutationInterface
85
    {
86 11
        if (!$queryResult->hasSelection() || !$queryResult->hasParent()) {
87 3
            return null;
88
        }
89 8
        $selection = $queryResult->getSelection();
90 8
        $parent = $queryResult->getParent();
91 8
        if ($parent instanceof ArrayValueInterface) {
92 4
            return new DeleteElementMutation($parent->getPath(), $selection->getPath());
93
        }
94 4
        if ($parent instanceof ObjectValueInterface) {
95 2
            return new DeletePropertyMutation($selection->getPath());
96
        }
97
98 2
        return null;
99
    }
100
101 20
    private function getMutationResult(
102
        QueryInterface $query,
103
        NodeValueInterface $rootNode,
104
        MutationInterface $mutation
105
    ): ResultInterface {
106
        $mutatedValue = $this
107 20
            ->mutator
108 20
            ->mutate($rootNode, $mutation);
109
110 20
        return null === $mutatedValue
111 10
            ? new NonExistingResult($query->getSource())
112 20
            : new ExistingResult($this->encoder, $this->decoder, $mutatedValue);
113
    }
114
115 9
    public function replace(
116
        QueryInterface $query,
117
        NodeValueInterface $rootNode,
118
        NodeValueInterface $value
119
    ): ResultInterface {
120 9
        $queryResult = $query($rootNode);
121
122 9
        return $queryResult->hasSelection()
123 4
            ? $this->getMutationResult(
124 4
                $query,
125 4
                $rootNode,
126 4
                new ReplaceMutation($value, $queryResult->getSelection()->getPath())
127
            )
128 9
            : new NonExistingResult($query->getSource());
129
    }
130
131 15
    public function add(QueryInterface $query, NodeValueInterface $rootNode, NodeValueInterface $value): ResultInterface
132
    {
133 15
        $mutation = $this->createAddMutation($query($rootNode), $value);
134
135 15
        return isset($mutation)
136 10
            ? $this->getMutationResult($query, $rootNode, $mutation)
137 15
            : new NonExistingResult($query->getSource());
138
    }
139
140 15
    private function createAddMutation(QueryResultInterface $queryResult, NodeValueInterface $value): ?MutationInterface
141
    {
142 15
        if (!$queryResult->hasParent() || !$queryResult->hasLastReference()) {
143 1
            return null;
144
        }
145 14
        $parent = $queryResult->getParent();
146 14
        $reference = $queryResult->getLastReference();
147 14
        if ($parent instanceof ObjectValueInterface) {
148 4
            return $queryResult->hasSelection()
149 2
                ? new ReplaceMutation($value, $queryResult->getSelection()->getPath())
150 4
                : new AppendPropertyMutation($value, $parent->getPath(), $reference->getPropertyName());
151
        }
152 10
        if ($parent instanceof ArrayValueInterface) {
153 9
            return $queryResult->hasSelection()
154 4
                ? $this->createInsertElementMutation($reference, $parent, $value)
155 9
                : $this->createAppendElementMutation($reference, $parent, $value);
156
        }
157
158 1
        return null;
159
    }
160
161 4
    private function createInsertElementMutation(
162
        ReferenceInterface $reference,
163
        NodeValueInterface $parent,
164
        NodeValueInterface $value
165
    ): ?MutationInterface {
166 4
        return $reference instanceof IndexReferenceInterface
167 2
            ? new InsertElementMutation($value, $parent->getPath(), $reference->getElementIndex())
168 4
            : null;
169
    }
170
171 5
    private function createAppendElementMutation(
172
        ReferenceInterface $reference,
173
        NodeValueInterface $parent,
174
        NodeValueInterface $value
175
    ): ?MutationInterface {
176
        switch (true) {
177 5
            case $reference instanceof NextIndexReferenceInterface:
178 2
                $elementIndex = null;
179 2
                break;
180
181 3
            case $reference instanceof IndexReferenceInterface:
182 2
                $elementIndex = $reference->getElementIndex();
183 2
                break;
184
185
            default:
186 1
                return null;
187
        }
188
189 4
        return new AppendElementMutation($value, $parent->getPath(), $elementIndex);
190
    }
191
}
192