Skip to content

Commit 8230d84

Browse files
authored
Merge pull request #11 from swaggest/issue-9
resolves #9
2 parents 81a403c + 59fb701 commit 8230d84

File tree

4 files changed

+52
-11
lines changed

4 files changed

+52
-11
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ Adds operation to `JsonPatch`.
107107
#### `apply`
108108
Applies patch to `JSON`-decoded data.
109109

110+
#### `setFlags`
111+
Alters default behavior.
112+
113+
Available flag:
114+
115+
* `JsonPatch::STRICT_MODE` Disallow converting empty array to object for key creation.
116+
110117
### `JsonPointer`
111118

112119
#### `escapeSegment`

src/JsonPatch.php

+22-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,24 @@
1919
*/
2020
class JsonPatch implements \JsonSerializable
2121
{
22+
/**
23+
* Disallow converting empty array to object for key creation
24+
* @see JsonPointer::STRICT_MODE
25+
*/
26+
const STRICT_MODE = 2;
27+
28+
private $flags = 0;
29+
30+
/**
31+
* @param int $options
32+
* @return $this
33+
*/
34+
public function setFlags($options)
35+
{
36+
$this->flags = $options;
37+
return $this;
38+
}
39+
2240
/** @var OpPath[] */
2341
private $operations = array();
2442

@@ -118,26 +136,26 @@ public function apply(&$original, $stopOnError = true)
118136
$pathItems = JsonPointer::splitPath($operation->path);
119137
switch (true) {
120138
case $operation instanceof Add:
121-
JsonPointer::add($original, $pathItems, $operation->value, false);
139+
JsonPointer::add($original, $pathItems, $operation->value, $this->flags);
122140
break;
123141
case $operation instanceof Copy:
124142
$fromItems = JsonPointer::splitPath($operation->from);
125143
$value = JsonPointer::get($original, $fromItems);
126-
JsonPointer::add($original, $pathItems, $value, false);
144+
JsonPointer::add($original, $pathItems, $value, $this->flags);
127145
break;
128146
case $operation instanceof Move:
129147
$fromItems = JsonPointer::splitPath($operation->from);
130148
$value = JsonPointer::get($original, $fromItems);
131149
JsonPointer::remove($original, $fromItems);
132-
JsonPointer::add($original, $pathItems, $value, false);
150+
JsonPointer::add($original, $pathItems, $value, $this->flags);
133151
break;
134152
case $operation instanceof Remove:
135153
JsonPointer::remove($original, $pathItems);
136154
break;
137155
case $operation instanceof Replace:
138156
JsonPointer::get($original, $pathItems);
139157
JsonPointer::remove($original, $pathItems);
140-
JsonPointer::add($original, $pathItems, $operation->value, false);
158+
JsonPointer::add($original, $pathItems, $operation->value, $this->flags);
141159
break;
142160
case $operation instanceof Test:
143161
$value = JsonPointer::get($original, $pathItems);

src/JsonPointer.php

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55

66
class JsonPointer
77
{
8+
/**
9+
* Create intermediate keys if they don't exist
10+
*/
11+
const RECURSIVE_KEY_CREATION = 1;
12+
13+
/**
14+
* Disallow converting empty array to object for key creation
15+
*/
16+
const STRICT_MODE = 2;
17+
818
/**
919
* @param string $key
1020
* @param bool $isURIFragmentId
@@ -76,10 +86,10 @@ private static function splitPathJsonString(array $pathItems)
7686
* @param mixed $holder
7787
* @param string[] $pathItems
7888
* @param mixed $value
79-
* @param bool $recursively
89+
* @param int $flags
8090
* @throws Exception
8191
*/
82-
public static function add(&$holder, $pathItems, $value, $recursively = true)
92+
public static function add(&$holder, $pathItems, $value, $flags = self::RECURSIVE_KEY_CREATION)
8393
{
8494
$ref = &$holder;
8595
while (null !== $key = array_shift($pathItems)) {
@@ -89,7 +99,7 @@ public static function add(&$holder, $pathItems, $value, $recursively = true)
8999
Exception::EMPTY_PROPERTY_NAME_UNSUPPORTED);
90100
}
91101

92-
if ($recursively) {
102+
if ($flags & self::RECURSIVE_KEY_CREATION) {
93103
$ref = &$ref->$key;
94104
} else {
95105
if (!isset($ref->$key) && count($pathItems)) {
@@ -102,17 +112,17 @@ public static function add(&$holder, $pathItems, $value, $recursively = true)
102112
$intKey = filter_var($key, FILTER_VALIDATE_INT);
103113
if ($ref === null && (false === $intKey || $intKey !== 0)) {
104114
$key = (string)$key;
105-
if ($recursively) {
115+
if ($flags & self::RECURSIVE_KEY_CREATION) {
106116
$ref = new \stdClass();
107117
$ref = &$ref->{$key};
108118
} else {
109119
throw new Exception('Non-existent path item: ' . $key);
110120
}
111-
} elseif ([] === $ref && false === $intKey && '-' !== $key) {
121+
} elseif ([] === $ref && 0 === ($flags & self::STRICT_MODE) && false === $intKey && '-' !== $key) {
112122
$ref = new \stdClass();
113123
$ref = &$ref->{$key};
114124
} else {
115-
if ($recursively && $ref === null) $ref = array();
125+
if ($flags & self::RECURSIVE_KEY_CREATION && $ref === null) $ref = array();
116126
if ('-' === $key) {
117127
$ref = &$ref[];
118128
} else {
@@ -122,7 +132,7 @@ public static function add(&$holder, $pathItems, $value, $recursively = true)
122132
if (false === $intKey) {
123133
throw new Exception('Invalid key for array operation');
124134
}
125-
if ($intKey > count($ref) && !$recursively) {
135+
if ($intKey > count($ref) && 0 === ($flags & self::RECURSIVE_KEY_CREATION)) {
126136
throw new Exception('Index is greater than number of items in array');
127137
} elseif ($intKey < 0) {
128138
throw new Exception('Negative index');

tests/src/Issues/Issue9Test.php

+6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Swaggest\JsonDiff\Tests\Issues;
44

5+
use Swaggest\JsonDiff\Exception;
56
use Swaggest\JsonDiff\JsonDiff;
7+
use Swaggest\JsonDiff\JsonPatch;
68

79
/**
810
* @see https://github.com/swaggest/json-diff/issues/9
@@ -18,5 +20,9 @@ public function testPatchApply()
1820
$this->assertNotEquals($new, $old);
1921
$patch->apply($old);
2022
$this->assertEquals($new, $old);
23+
24+
$old = json_decode(json_encode(["emptyObject" => []]));
25+
$this->setExpectedException(get_class(new Exception()), 'Invalid key for array operation');
26+
$patch->setFlags(JsonPatch::STRICT_MODE)->apply($old);
2127
}
2228
}

0 commit comments

Comments
 (0)