Skip to content

Commit

Permalink
JsonPointer specification is now handled with a dedicated class
Browse files Browse the repository at this point in the history
  • Loading branch information
blancks committed Nov 12, 2024
1 parent 31f4db5 commit d5eff9c
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 22 deletions.
18 changes: 1 addition & 17 deletions src/json/crud/CrudTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function delete(mixed &$document, string $path): mixed
*/
private function pathResolver(mixed &$document, string $path): array
{
$tokens = $this->pathToTokens($path);
$tokens = $this->getTokensFromPointer($path);
$pathLength = count($tokens);

if ($pathLength === 0) {
Expand Down Expand Up @@ -119,20 +119,4 @@ private function pathResolver(mixed &$document, string $path): array

throw new UnknownPathException(sprintf('path "%s" does not exists', $path), $path);
}

/**
* Returns the given JSON Pointer (RFC-6901) as an array of tokens
* @link https://datatracker.ietf.org/doc/html/rfc6901#section-3
* @param string $path the JSON Pointer
* @return string[]
*/
private function pathToTokens(string $path): array
{
if ($path !== '') {
$path = strtr(substr($path, 1), ['/' => '~ ', '~1' => '/', '~0' => '~']);
return explode('~ ', $path);
}

return [];
}
}
27 changes: 26 additions & 1 deletion src/json/handlers/BasicJsonHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,24 @@
ValueAccessorInterface
};
use blancks\JsonPatch\json\crud\CrudTrait;
use blancks\JsonPatch\json\pointer\{
JsonPointer6901,
JsonPointerHandlerAwareInterface,
JsonPointerHandlerAwareTrait,
JsonPointerHandlerInterface
};

/**
* Responsibile of handling document encoding/decoding and CRUD operations
*/
class BasicJsonHandler implements
JsonHandlerInterface,
JsonPointerHandlerAwareInterface,
ArrayAccessorAwareInterface,
ObjectAccessorAwareInterface,
ValueAccessorAwareInterface
{
use JsonPointerHandlerAwareTrait;
use ArrayAccessorAwareTrait;
use ObjectAccessorAwareTrait;
use ValueAccessorAwareTrait;
Expand All @@ -36,11 +44,13 @@ class BasicJsonHandler implements
public function __construct(
?ArrayAccessorInterface $ArrayAccessor = null,
?ObjectAccessorInterface $ObjectAccessor = null,
?ValueAccessorInterface $ValueAccessor = null
?ValueAccessorInterface $ValueAccessor = null,
?JsonPointerHandlerInterface $JsonPointerHandler = null
) {
$this->setArrayAccessor($ArrayAccessor ?? new ArrayAccessor);
$this->setObjectAccessor($ObjectAccessor ?? new ObjectAccessor);
$this->setValueAccessor($ValueAccessor ?? new ValueAccessor);
$this->setJsonPointerHandler($JsonPointerHandler ?? new JsonPointer6901);
}

/**
Expand Down Expand Up @@ -86,4 +96,19 @@ public function decode(string $json, array $options = []): mixed
throw new MalformedDocumentException('Error while decoding JSON: ' . $e->getMessage(), null, $e);
}
}

/**
* Returns true if $path is a valid JSON Pointer
* @param string $pointer
* @return bool
*/
public function isValidPointer(string $pointer): bool
{
return $this->jsonPointerHandler->isValidPointer($pointer);
}

public function getTokensFromPointer(string $pointer): array
{
return $this->jsonPointerHandler->getTokensFromPointer($pointer);
}
}
3 changes: 2 additions & 1 deletion src/json/handlers/JsonHandlerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace blancks\JsonPatch\json\handlers;

use blancks\JsonPatch\json\crud\CrudInterface;
use blancks\JsonPatch\json\pointer\JsonPointerHandlerInterface;

interface JsonHandlerInterface extends CrudInterface
interface JsonHandlerInterface extends CrudInterface, JsonPointerHandlerInterface
{
/**
* @param mixed $document
Expand Down
35 changes: 35 additions & 0 deletions src/json/pointer/JsonPointer6901.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);

namespace blancks\JsonPatch\json\pointer;

/**
* Handles JSON Pointer as per RFC-6901
* @link https://datatracker.ietf.org/doc/html/rfc6901
*/
class JsonPointer6901 implements JsonPointerHandlerInterface
{
/**
* Tells if the pointer is valid
* @param string $pointer
* @return bool
*/
public function isValidPointer(string $pointer): bool
{
return $pointer === '' || $pointer[0] === '/';
}

/**
* Returns the token list of the given $pointer
* @param string $pointer the JSON Pointer
* @return string[]
*/
public function getTokensFromPointer(string $pointer): array
{
if ($pointer !== '') {
$pointer = strtr(substr($pointer, 1), ['/' => '~ ', '~1' => '/', '~0' => '~']);
return explode('~ ', $pointer);
}

return [];
}
}
8 changes: 8 additions & 0 deletions src/json/pointer/JsonPointerHandlerAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types=1);

namespace blancks\JsonPatch\json\pointer;

interface JsonPointerHandlerAwareInterface
{
public function setJsonPointerHandler(JsonPointerHandlerInterface $jsonPointerHandler): void;
}
13 changes: 13 additions & 0 deletions src/json/pointer/JsonPointerHandlerAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace blancks\JsonPatch\json\pointer;

trait JsonPointerHandlerAwareTrait
{
protected JsonPointerHandlerInterface $jsonPointerHandler;

public function setJsonPointerHandler(JsonPointerHandlerInterface $jsonPointerHandler): void
{
$this->jsonPointerHandler = $jsonPointerHandler;
}
}
15 changes: 15 additions & 0 deletions src/json/pointer/JsonPointerHandlerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace blancks\JsonPatch\json\pointer;

interface JsonPointerHandlerInterface
{
public function isValidPointer(string $pointer): bool;

/**
* Should return the given JSON Pointer as an array of tokens
* @param string $pointer the JSON Pointer
* @return string[]
*/
public function getTokensFromPointer(string $pointer): array;
}
4 changes: 2 additions & 2 deletions src/operations/PatchValidationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ protected function assertValidValue(object $patch): void

protected function assertValidJsonPointer(string $pointer): void
{
if ($pointer !== '' && $pointer[0] !== '/') {
throw new MalformedPathException(sprintf('path "%s" is missing a leading slash', $pointer), $pointer);
if (!$this->JsonHandler->isValidPointer($pointer)) {
throw new MalformedPathException(sprintf('path "%s" is not a valid JSON Pointer', $pointer), $pointer);
}
}
}
22 changes: 21 additions & 1 deletion tests/json/crud/CrudTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
use blancks\JsonPatch\json\accessors\ValueAccessorInterface;
use blancks\JsonPatch\json\crud\CrudInterface;
use blancks\JsonPatch\json\crud\CrudTrait;
use blancks\JsonPatch\json\pointer\JsonPointer6901;
use blancks\JsonPatch\json\pointer\JsonPointerHandlerAwareInterface;
use blancks\JsonPatch\json\pointer\JsonPointerHandlerAwareTrait;
use blancks\JsonPatch\json\pointer\JsonPointerHandlerInterface;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\MockObject\MockObject;
Expand Down Expand Up @@ -40,12 +44,28 @@ class CrudTraitTest extends TestCase
*/
protected function setUp(): void
{
$this->crud = new class implements CrudInterface {
$this->crud = new class implements CrudInterface, JsonPointerHandlerInterface, JsonPointerHandlerAwareInterface {
use CrudTrait;
use JsonPointerHandlerAwareTrait;

public ArrayAccessorInterface $ArrayAccessor;
public ObjectAccessorInterface $ObjectAccessor;
public ValueAccessorInterface $ValueAccessor;

public function __construct()
{
$this->setJsonPointerHandler(new JsonPointer6901);
}

public function isValidPointer(string $pointer): bool
{
return $this->jsonPointerHandler->isValidPointer($pointer);
}

public function getTokensFromPointer(string $pointer): array
{
return $this->jsonPointerHandler->getTokensFromPointer($pointer);
}
};
$this->ArrayAccessorMock = $this->createMock(ArrayAccessorInterface::class);
$this->ObjectAccessorMock = $this->createMock(ObjectAccessorInterface::class);
Expand Down

0 comments on commit d5eff9c

Please sign in to comment.