Created
July 22, 2014 19:58
-
-
Save pjdietz/0f53907ce95ea586664a to your computer and use it in GitHub Desktop.
$ref Resolver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Iterates through an object or array and resolves or "flatten" and $ref | |
* properties by reading the object the reference points to and augmenting | |
* the containing object with the result. | |
* | |
* This class works with any stdClass object, but is mostly likely to be | |
* useful for working with JSON Schema documents and Swagger configurations. | |
*/ | |
class RefResolver | |
{ | |
/** | |
* Function that given a string URI returns an object or null. | |
* @var callable | |
*/ | |
private $readReferenceFn; | |
/** | |
* Create new ref flattener. | |
* | |
* Optionally provide a custom function for reading a resource. The | |
* callabl must accept one argument, the string value of a $ref property, | |
* and return the object resolved at that reference or null. | |
* | |
* @param callable $readReferenceFn | |
*/ | |
public function __construct($readReferenceFn = null) | |
{ | |
$this->readReferenceFn = $readReferenceFn; | |
} | |
/** | |
* Resolve $ref references in the oject's structure by reading the object | |
* at the reference and augmenting the contain object. | |
* | |
* @param object|array $obj Object (or array) to flesh out | |
*/ | |
public function resolve(&$obj) | |
{ | |
// Flatten each member of an array. | |
if (is_array($obj)) { | |
foreach ($obj as $v) { | |
$this->resolve($v); | |
} | |
return; | |
} | |
// Do nothing if not an array or object. | |
if (!is_object($obj)) { | |
return; | |
} | |
// Check if the object contains a $ref member. | |
// If it does, attempt to read the results of the reference. | |
if (isset($obj->{'$ref'})) { | |
$resolved = $this->readReference($obj->{'$ref'}); | |
// Remove $ref and augment $obj with the resolved reference. | |
if (is_object($resolved)) { | |
unset($obj->{'$ref'}); | |
$this->resolve($resolved); | |
$this->augment($obj, $resolved); | |
} | |
} | |
foreach ($obj as $k => $v) { | |
$this->resolve($v); | |
} | |
} | |
/** | |
* Read an object identified by the value of a $ref member. | |
* | |
* If the instance's readReferenceFn member is set, call it, passing $ref, | |
* and return the result. Otherwise, use file_get_contents() and | |
* json_decode() to read the reference. | |
* | |
* @param string $ref Value of a $ref property | |
* @return object|null | |
*/ | |
private function readReference($ref) | |
{ | |
if (is_callable($this->readReferenceFn)) { | |
$callable = $this->readReferenceFn; | |
return $callable($ref); | |
} | |
$contents = @file_get_contents($ref); | |
if ($contents) { | |
return json_decode($contents); | |
} | |
return null; | |
} | |
/** | |
* Merge the members of $source onto $target | |
* | |
* @param object $target | |
* @param object $source | |
*/ | |
private function augment(&$target, $source) | |
{ | |
foreach ($source as $property => $value) { | |
$target->{$property} = $value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note, there's currently nothing in here to safeguard against circular references.