Completed
Push — master ( b9da3c...daa7f0 )
by Viacheslav
26s queued 12s
created

JsonPatch::import()   D

Complexity

Conditions 19
Paths 85

Size

Total Lines 67
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 19

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 50
c 1
b 0
f 0
nc 85
nop 1
dl 0
loc 67
ccs 47
cts 47
cp 1
crap 19
rs 4.5166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Swaggest\JsonDiff;
4
5
use Swaggest\JsonDiff\JsonPatch\Add;
6
use Swaggest\JsonDiff\JsonPatch\Copy;
7
use Swaggest\JsonDiff\JsonPatch\Move;
8
use Swaggest\JsonDiff\JsonPatch\OpPath;
9
use Swaggest\JsonDiff\JsonPatch\OpPathFrom;
10
use Swaggest\JsonDiff\JsonPatch\OpPathValue;
11
use Swaggest\JsonDiff\JsonPatch\Remove;
12
use Swaggest\JsonDiff\JsonPatch\Replace;
13
use Swaggest\JsonDiff\JsonPatch\Test;
14
15
/**
16
 * JSON Patch is specified in [RFC 6902](http://tools.ietf.org/html/rfc6902) from the IETF.
17
 *
18
 * Class JsonPatch
19
 */
20
class JsonPatch implements \JsonSerializable
21
{
22
    /**
23
     * Disallow converting empty array to object for key creation
24
     * @see JsonPointer::STRICT_MODE
25
     */
26
    const STRICT_MODE = 2;
27
28
    /**
29
     * Allow associative arrays to mimic JSON objects (not recommended)
30
     */
31
    const TOLERATE_ASSOCIATIVE_ARRAYS = 8;
32
33
34
    private $flags = 0;
35
36
    /**
37
     * @param int $options
38
     * @return $this
39
     */
40 2
    public function setFlags($options)
41
    {
42 2
        $this->flags = $options;
43 2
        return $this;
44
    }
45
46
    /** @var OpPath[] */
47
    private $operations = array();
48
49
    /**
50
     * @param array $data
51
     * @return JsonPatch
52
     * @throws Exception
53
     */
54 108
    public static function import(array $data)
55
    {
56 108
        $result = new JsonPatch();
57 108
        foreach ($data as $operation) {
58
            /** @var OpPath|OpPathValue|OpPathFrom|array $operation */
59 102
            if (is_array($operation)) {
60 4
                $operation = (object)$operation;
61
            }
62
            if (!is_object($operation)) {
63 102
                throw new Exception('Invalid patch operation - should be a JSON object');
64 1
            }
65
66 101
            if (!isset($operation->op)) {
67 1
                throw new MissingFieldException('op', $operation);
68
            }
69
            if (!isset($operation->path)) {
70 100
                throw new MissingFieldException('path', $operation);
71 100
            }
72 100
73 40
            if (!is_string($operation->op)) {
74 40
                throw new InvalidFieldTypeException('op', 'string', $operation);
75 64
            }
76 6
            if (!is_string($operation->path)) {
77 6
                throw new InvalidFieldTypeException('path', 'string', $operation);
78 58
            }
79 8
80 8
            $op = null;
81 50
            switch ($operation->op) {
82 18
                case Add::OP:
83 18
                    $op = new Add();
84 36
                    break;
85 19
                case Copy::OP:
86 19
                    $op = new Copy();
87 20
                    break;
88 18
                case Move::OP:
89 18
                    $op = new Move();
90
                    break;
91 2
                case Remove::OP:
92
                    $op = new Remove();
93 98
                    break;
94 98
                case Replace::OP:
95 71
                    $op = new Replace();
96 5
                    break;
97
                case Test::OP:
98 66
                    $op = new Test();
99 32
                    break;
100 14
                default:
101 3
                    throw new UnknownOperationException($operation);
102
            }
103 11
            $op->path = $operation->path;
104
            if ($op instanceof OpPathValue) {
105 90
                if (property_exists($operation, 'value')) {
106
                    $op->value = $operation->value;
107 96
                } else {
108
                    throw new MissingFieldException('value', $operation);
109
                }
110 7
            } elseif ($op instanceof OpPathFrom) {
111
                if (!isset($operation->from)) {
112 7
                    throw new MissingFieldException('from', $operation);
113 7
                } elseif (!is_string($operation->from)) {
114 7
                    throw new InvalidFieldTypeException('from', 'string', $operation);
115
                }
116
                $op->from = $operation->from;
117 7
            }
118
            $result->operations[] = $op;
119
        }
120 33
        return $result;
121
    }
122 33
123 33
    public static function export(JsonPatch $patch)
124
    {
125
        $result = array();
126 6
        foreach ($patch->operations as $operation) {
127
            $result[] = (object)(array)$operation;
128 6
        }
129
130
        return $result;
131
    }
132
133
    public function op(OpPath $op)
134
    {
135
        $this->operations[] = $op;
136
        return $this;
137 100
    }
138
139 100
    #[\ReturnTypeWillChange]
140 100
    public function jsonSerialize()
141
    {
142 94
        return self::export($this);
143
    }
144 94
145 40
    /**
146 32
     * @param mixed $original
147 57
     * @param bool $stopOnError
148 5
     * @return Exception[] array of errors
149 5
     * @throws Exception
150 4
     */
151 4
    public function apply(&$original, $stopOnError = true)
152 53
    {
153 7
        $errors = array();
154 7
        foreach ($this->operations as $operation) {
155 6
            try {
156 6
                // track the current pointer field so we can use it for a potential PathException
157 6
                $pointerField = 'path';
158 46
                $pathItems = JsonPointer::splitPath($operation->path);
159 18
                switch (true) {
160 14
                    case $operation instanceof Add:
161 32
                        JsonPointer::add($original, $pathItems, $operation->value, $this->flags);
162 18
                        break;
163 16
                    case $operation instanceof Copy:
164 16
                        $pointerField = 'from';
165 16
                        $fromItems = JsonPointer::splitPath($operation->from);
166 18
                        $value = JsonPointer::get($original, $fromItems);
167 18
                        $pointerField = 'path';
168 15
                        JsonPointer::add($original, $pathItems, $value, $this->flags);
169 15
                        break;
170 15
                    case $operation instanceof Move:
171 3
                        $pointerField = 'from';
172 3
                        $fromItems = JsonPointer::splitPath($operation->from);
173
                        $value = JsonPointer::get($original, $fromItems);
174 73
                        JsonPointer::remove($original, $fromItems, $this->flags);
175
                        $pointerField = 'path';
176 23
                        JsonPointer::add($original, $pathItems, $value, $this->flags);
177 23
                        break;
178 21
                    case $operation instanceof Remove:
179
                        JsonPointer::remove($original, $pathItems, $this->flags);
180 2
                        break;
181
                    case $operation instanceof Replace:
182
                        JsonPointer::get($original, $pathItems);
183
                        JsonPointer::remove($original, $pathItems, $this->flags);
184 80
                        JsonPointer::add($original, $pathItems, $operation->value, $this->flags);
185
                        break;
186
                    case $operation instanceof Test:
187
                        $value = JsonPointer::get($original, $pathItems);
188
                        $diff = new JsonDiff($operation->value, $value,
189
                            JsonDiff::STOP_ON_DIFF);
190
                        if ($diff->getDiffCnt() !== 0) {
191
                            throw new PatchTestOperationFailedException($operation, $value);
192
                        }
193
                        break;
194
                }
195
            } catch (JsonPointerException $jsonPointerException) {
196
                $pathException = new PathException(
197
                    $jsonPointerException->getMessage(),
198
                    $operation,
199
                    $pointerField,
200
                    $jsonPointerException->getCode()
201
                );
202
                if ($stopOnError) {
203
                    throw $pathException;
204
                } else {
205
                    $errors[] = $pathException;
206
                }
207
            } catch (Exception $exception) {
208
                if ($stopOnError) {
209
                    throw $exception;
210
                } else {
211
                    $errors[] = $exception;
212
                }
213
            }
214
        }
215
        return $errors;
216
    }
217
}
218