Skip to content

Commit

Permalink
fault-tolerant patch apply
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop committed Mar 19, 2018
1 parent 67f2acf commit 4554ad2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 34 deletions.
80 changes: 46 additions & 34 deletions src/JsonPatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,45 +106,57 @@ public function jsonSerialize()

/**
* @param mixed $original
* @param bool $stopOnError
* @return Exception[] array of errors
* @throws Exception
*/
public function apply(&$original)
public function apply(&$original, $stopOnError = true)
{
$errors = array();
foreach ($this->operations as $operation) {
$pathItems = JsonPointer::splitPath($operation->path);
switch (true) {
case $operation instanceof Add:
JsonPointer::add($original, $pathItems, $operation->value, false);
break;
case $operation instanceof Copy:
$fromItems = JsonPointer::splitPath($operation->from);
$value = JsonPointer::get($original, $fromItems);
JsonPointer::add($original, $pathItems, $value, false);
break;
case $operation instanceof Move:
$fromItems = JsonPointer::splitPath($operation->from);
$value = JsonPointer::get($original, $fromItems);
JsonPointer::remove($original, $fromItems);
JsonPointer::add($original, $pathItems, $value, false);
break;
case $operation instanceof Remove:
JsonPointer::remove($original, $pathItems);
break;
case $operation instanceof Replace:
JsonPointer::get($original, $pathItems);
JsonPointer::remove($original, $pathItems);
JsonPointer::add($original, $pathItems, $operation->value, false);
break;
case $operation instanceof Test:
$value = JsonPointer::get($original, $pathItems);
$diff = new JsonDiff($operation->value, $value,
JsonDiff::STOP_ON_DIFF);
if ($diff->getDiffCnt() !== 0) {
throw new Exception('Test operation ' . json_encode($operation, JSON_UNESCAPED_SLASHES)
. ' failed: ' . json_encode($value));
}
break;
try {
$pathItems = JsonPointer::splitPath($operation->path);
switch (true) {
case $operation instanceof Add:
JsonPointer::add($original, $pathItems, $operation->value, false);
break;
case $operation instanceof Copy:
$fromItems = JsonPointer::splitPath($operation->from);
$value = JsonPointer::get($original, $fromItems);
JsonPointer::add($original, $pathItems, $value, false);
break;
case $operation instanceof Move:
$fromItems = JsonPointer::splitPath($operation->from);
$value = JsonPointer::get($original, $fromItems);
JsonPointer::remove($original, $fromItems);
JsonPointer::add($original, $pathItems, $value, false);
break;
case $operation instanceof Remove:
JsonPointer::remove($original, $pathItems);
break;
case $operation instanceof Replace:
JsonPointer::get($original, $pathItems);
JsonPointer::remove($original, $pathItems);
JsonPointer::add($original, $pathItems, $operation->value, false);
break;
case $operation instanceof Test:
$value = JsonPointer::get($original, $pathItems);
$diff = new JsonDiff($operation->value, $value,
JsonDiff::STOP_ON_DIFF);
if ($diff->getDiffCnt() !== 0) {
throw new Exception('Test operation ' . json_encode($operation, JSON_UNESCAPED_SLASHES)
. ' failed: ' . json_encode($value));
}
break;
}
} catch (Exception $exception) {
if ($stopOnError) {
throw $exception;
} else {
$errors[] = $exception;
}
}
}
return $errors;
}
}
13 changes: 13 additions & 0 deletions tests/src/JsonPatchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,17 @@ public function testApply()
$this->assertSame(array('AAA', 'AAA'), $original);
}

public function testApplyContinueOnError()
{
$p = new JsonPatch();
$p->op(new JsonPatch\Test('/missing', 1));
$p->op(new JsonPatch\Copy('/1', '/0'));
$p->op(new JsonPatch\Test('/missing2', null));
$original = array('AAA');
$errors = $p->apply($original, false);
$this->assertSame(array('AAA', 'AAA'), $original);
$this->assertSame('Key not found: missing', $errors[0]->getMessage());
$this->assertSame('Key not found: missing2', $errors[1]->getMessage());
}

}

0 comments on commit 4554ad2

Please sign in to comment.