Processor   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Test Coverage

Coverage 97.56%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 78
c 3
b 0
f 0
dl 0
loc 162
ccs 80
cts 82
cp 0.9756
rs 10
wmc 30

11 Methods

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