Passed
Push — master ( ec8827...deea55 )
by Edward
02:26
created

OperationFactory::extractFromPointer()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 11
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 16
rs 9.9
1
<?php
2
declare(strict_types=1);
3
4
namespace Remorhaz\JSON\Patch\Operation;
5
6
use Remorhaz\JSON\Data\Comparator\ComparatorInterface;
7
use Remorhaz\JSON\Data\Value\NodeValueInterface;
8
use Remorhaz\JSON\Pointer\Processor\ProcessorInterface as PointerProcessorInterface;
9
use Remorhaz\JSON\Pointer\Query\QueryFactoryInterface as PointerQueryFactoryInterface;
10
use Remorhaz\JSON\Pointer\Query\QueryInterface;
11
use function is_string;
12
13
final class OperationFactory implements OperationFactoryInterface
14
{
15
16
    private const OPERATION_ADD = 'add';
17
18
    private const OPERATION_REMOVE = 'remove';
19
20
    private const OPERATION_REPLACE = 'replace';
21
22
    private const OPERATION_TEST = 'test';
23
24
    private const OPERATION_COPY = 'copy';
25
26
    private const OPERATION_MOVE = 'move';
27
28
    private $pointerQueryFactory;
29
30
    private $pointerProcessor;
31
32
    private $equalComparator;
33
34
    public function __construct(
35
        PointerQueryFactoryInterface $pointerQueryFactory,
36
        PointerProcessorInterface $pointerProcessor,
37
        ComparatorInterface $equalComparator
38
    ) {
39
        $this->pointerQueryFactory = $pointerQueryFactory;
40
        $this->pointerProcessor = $pointerProcessor;
41
        $this->equalComparator = $equalComparator;
42
    }
43
44
    public function fromJson(NodeValueInterface $jsonValue, int $index): OperationInterface
45
    {
46
        $operationCode = $this->getOperationCode($jsonValue, $index);
47
        switch ($operationCode) {
48
            case self::OPERATION_ADD:
49
                return new AddOperation(
50
                    $index,
51
                    $this->extractPathPointer($jsonValue, $index),
52
                    $this->extractValue($jsonValue, $index)
53
                );
54
55
            case self::OPERATION_REMOVE:
56
                return new RemoveOperation(
57
                    $index,
58
                    $this->extractPathPointer($jsonValue, $index)
59
                );
60
61
            case self::OPERATION_REPLACE:
62
                return new ReplaceOperation(
63
                    $index,
64
                    $this->extractPathPointer($jsonValue, $index),
65
                    $this->extractValue($jsonValue, $index)
66
                );
67
68
            case self::OPERATION_TEST:
69
                return new TestOperation(
70
                    $index,
71
                    $this->extractPathPointer($jsonValue, $index),
72
                    $this->extractValue($jsonValue, $index),
73
                    $this->equalComparator
74
                );
75
76
            case self::OPERATION_COPY:
77
                return new CopyOperation(
78
                    $index,
79
                    $this->extractPathPointer($jsonValue, $index),
80
                    $this->extractFromPointer($jsonValue, $index)
81
                );
82
83
            case self::OPERATION_MOVE:
84
                return new MoveOperation(
85
                    $index,
86
                    $this->extractPathPointer($jsonValue, $index),
87
                    $this->extractFromPointer($jsonValue, $index)
88
                );
89
        }
90
91
        throw new Exception\UnknownOperationCodeException($index, $operationCode);
92
    }
93
94
    private function getOperationCode(NodeValueInterface $jsonValue, int $index): string
95
    {
96
        $result = $this
97
            ->pointerProcessor
98
            ->select($this->pointerQueryFactory->createQuery('/op'), $jsonValue);
99
        if (!$result->exists()) {
100
            throw new Exception\OperationCodeNotFoundException($index);
101
        }
102
        $operationCode = $result->decode();
103
        if (is_string($operationCode)) {
104
            return $operationCode;
105
        }
106
107
        throw new Exception\InvalidOperationCodeException($operationCode, $index);
108
    }
109
110
    private function extractPathPointer(NodeValueInterface $operation, int $index): QueryInterface
111
    {
112
        $result = $this
113
            ->pointerProcessor
114
            ->select($this->pointerQueryFactory->createQuery('/path'), $operation);
115
        if (!$result->exists()) {
116
            throw new Exception\PathNotFoundException($index, 'path');
117
        }
118
        $path = $result->decode();
119
        if (!is_string($path)) {
120
            throw new Exception\InvalidPathException($index, 'path', $path);
121
        }
122
123
        return $this
124
            ->pointerQueryFactory
125
            ->createQuery($path);
126
    }
127
128
    private function extractFromPointer(NodeValueInterface $operation, int $index): QueryInterface
129
    {
130
        $result = $this
131
            ->pointerProcessor
132
            ->select($this->pointerQueryFactory->createQuery('/from'), $operation);
133
        if (!$result->exists()) {
134
            throw new Exception\PathNotFoundException($index, 'from');
135
        }
136
        $path = $result->decode();
137
        if (!is_string($path)) {
138
            throw new Exception\InvalidPathException($index, 'from', $path);
139
        }
140
141
        return $this
142
            ->pointerQueryFactory
143
            ->createQuery($path);
144
    }
145
146
    private function extractValue(NodeValueInterface $operation, int $index): NodeValueInterface
147
    {
148
        $result = $this
149
            ->pointerProcessor
150
            ->select($this->pointerQueryFactory->createQuery('/value'), $operation);
151
152
        if ($result->exists()) {
153
            return $result->get();
154
        }
155
156
        throw new Exception\ValueNotFoundException($index);
157
    }
158
}
159