Skip to content

Commit

Permalink
Merge pull request #4 from vanilla/feature/reference-trait
Browse files Browse the repository at this point in the history
Add the ReferenceResolverTrait
  • Loading branch information
tburry authored Feb 23, 2020
2 parents a5a03b8 + 360527b commit 2486e1f
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 71 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"autoload-dev": {
"psr-4": {
"Garden\\JSON\\Tests\\": "src"
"Garden\\JSON\\Tests\\": "tests"
}
},
"require-dev": {
Expand Down
81 changes: 81 additions & 0 deletions src/ReferenceResolverTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/**
* @author Todd Burry <[email protected]>
* @copyright 2009-2020 Vanilla Forums Inc.
* @license MIT
*/

namespace Garden\JSON;


trait ReferenceResolverTrait {
/**
* Escape a JSON reference field.
*
* @param string $field The reference field to escape.
* @return string Returns an escaped reference.
*/
private static function escapeRef(string $field): string {
return str_replace(['~', '/', '$'], ['~0', '~1', '~2'], $field);
}

/**
* Unescape a JSON reference segment.
*
* @param string $str The segment to unescapeRef.
* @return string Returns the unescaped string.
*/
private static function unescapeRef(string $str): string {
return str_replace(['~2', '~1', '~0'], ['$', '/', '~'], $str);
}

/**
* Explode a references into its individual parts.
*
* @param string $ref A JSON reference.
* @return string[] The individual parts of the reference.
*/
private static function explodeRef(string $ref): array {
return array_map([self::class, 'unescapeRef'], explode('/', $ref));
}

/**
* Resolve a JSON reference.
*
* @param int|string $ref The reference to resolve.
* @param mixed $context The current data context to lookup.
* @param mixed $root The root data context for absolute references.
* @param bool $found Set to **true** if the reference was found or **false** otherwise.
* @return mixed Returns the value at the reference.
*/
private function resolveReference($ref, $context, $root, bool &$found = null) {
$found = true;

if ($ref === '') {
return $context;
} elseif ($ref === '/') {
return $root;
} elseif (is_int($ref)) {
return $context[$ref];
} elseif ($ref[0] === '/') {
$ref = substr($ref, 1);
$context = $root;
}

$parts = self::explodeRef($ref);
$result = $context;
foreach ($parts as $key) {
if (!is_array($result)) {
$found = false;
return null;
} elseif (array_key_exists($key, $result)) {
$result = $result[$key];
} else {
$found = false;
return null;
}
}

return $result;
}
}
72 changes: 2 additions & 70 deletions src/Transformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* A class that transforms data based on a specification.
*/
final class Transformer {
use ReferenceResolverTrait;

/**
* @var string|array The transform spec.
*/
Expand Down Expand Up @@ -88,76 +90,6 @@ private function transformInternal($spec, $data, $root, string $path) {
return $result;
}

/**
* Resolve a JSON reference.
*
* @param int|string $ref The reference to resolve.
* @param mixed $context The current data context to lookup.
* @param mixed $root The root data context for absolute references.
* @param bool $found Set to **true** if the reference was found or **false** otherwise.
* @return mixed Returns the value at the reference.
*/
private function resolveReference($ref, $context, $root, bool &$found = null) {
$found = true;

if ($ref === '') {
return $context;
} elseif ($ref === '/') {
return $root;
} elseif (is_int($ref)) {
return $context[$ref];
} elseif ($ref[0] === '/') {
$ref = substr($ref, 1);
$context = $root;
}

$parts = self::explodeRef($ref);
$result = $context;
foreach ($parts as $key) {
if (!is_array($result)) {
$found = false;
return null;
} elseif (array_key_exists($key, $result)) {
$result = $result[$key];
} else {
$found = false;
return null;
}
}

return $result;
}

/**
* Escape a JSON reference field.
*
* @param string $field The reference field to escape.
* @return string Returns an escaped reference.
*/
private static function escapeRef(string $field): string {
return str_replace(['~', '/', '$'], ['~0', '~1', '~2'], $field);
}

/**
* Unescape a JSON reference segment.
*
* @param string $str The segment to unescapeRef.
* @return string Returns the unescaped string.
*/
private static function unescapeRef(string $str): string {
return str_replace(['~2', '~1', '~0'], ['$', '/', '~'], $str);
}

/**
* Explode a references into its individual parts.
*
* @param string $ref A JSON reference.
* @return string[] The individual parts of the reference.
*/
private static function explodeRef(string $ref): array {
return array_map([self::class, 'unescapeRef'], explode('/', $ref));
}

/**
* Resolve a control expression.
*
Expand Down

0 comments on commit 2486e1f

Please sign in to comment.