Passed
Push — master ( 3a32e2...77143f )
by Edward
04:21
created

Processor::createAddMutation()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

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