Skip to content

Commit

Permalink
Merge pull request #41 from swaggest/deep-ref-export
Browse files Browse the repository at this point in the history
keep intermediate references in path
  • Loading branch information
vearutop authored May 14, 2018
2 parents dfe67fc + fcefa57 commit 98ffcb9
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 10 deletions.
3 changes: 3 additions & 0 deletions src/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class Context extends MagicMap
public $version = Schema::VERSION_AUTO;

public $exportedDefinitions = [];

public $isRef = false;

/**
* @param boolean $skipValidation
* @return Context
Expand Down
38 changes: 28 additions & 10 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,9 @@ private function processObject($data, Context $options, $path, $result = null)
try {
$refResult = $this->process($data, $options, $path . '->$ref:' . $refString, $result);
if ($refResult instanceof ObjectItemContract) {
if ($refResult->getFromRefs()) {
$refResult = clone $refResult; // @todo check performance, consider option
}
$refResult->setFromRef($refString);
}
$ref->setImported($refResult);
Expand Down Expand Up @@ -1025,24 +1028,39 @@ public function process($data, Context $options, $path = '#', $result = null)
if ('#' === $path) {
$injectDefinitions = new ScopeExit(function () use ($result, $options) {
foreach ($options->exportedDefinitions as $ref => $data) {
JsonPointer::add($result, JsonPointer::splitPath($ref), $data,
JsonPointer::SKIP_IF_ISSET + JsonPointer::RECURSIVE_KEY_CREATION);
if ($data !== null) {
JsonPointer::add($result, JsonPointer::splitPath($ref), $data,
/*JsonPointer::SKIP_IF_ISSET + */
JsonPointer::RECURSIVE_KEY_CREATION);
}
}
});
}

if ('#' !== $path && $ref = $data->getFromRef()) {
if ($ref[0] === '#') {
if (isset($options->exportedDefinitions[$ref])) {
$result->{self::PROP_REF} = $ref;
return $result;
} elseif (!array_key_exists($ref, $options->exportedDefinitions)) {
if ($options->isRef) {
$options->isRef = false;
} else {
if ('#' !== $path && $refs = $data->getFromRefs()) {
$ref = $refs[0];
if (!array_key_exists($ref, $options->exportedDefinitions) && strpos($ref, '://') === false) {
$exported = null;
$options->exportedDefinitions[$ref] = &$exported;
$options->isRef = true;
$exported = $this->process($data, $options, $ref);
$result->{self::PROP_REF} = $ref;
return $result;
unset($exported);
}

for ($i = 1; $i < count($refs); $i++) {
$ref = $refs[$i];
if (!array_key_exists($ref, $options->exportedDefinitions) && strpos($ref, '://') === false) {
$exported = new \stdClass();
$exported->{self::PROP_REF} = $refs[$i - 1];
$options->exportedDefinitions[$ref] = $exported;
}
}

$result->{self::PROP_REF} = $refs[count($refs) - 1];
return $result;
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/Structure/ObjectItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

namespace Swaggest\JsonSchema\Structure;

/**
* @method getNestedObject($className);
* @method setNestedProperty($propertyName, $value, Egg $nestedEgg);
* @method addAdditionalPropertyName($name);
* @method setDocumentPath($path);
* @method setFromRef($ref);
* @method string|null getFromRef();
* @method string[]|null getFromRefs();
*/
class ObjectItem implements ObjectItemContract
{
use ObjectItemTrait;
Expand Down
10 changes: 10 additions & 0 deletions src/Structure/ObjectItemContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,15 @@ public function setNestedProperty($propertyName, $value, Egg $nestedEgg);
public function addAdditionalPropertyName($name);
public function setDocumentPath($path);
public function setFromRef($ref);

/**
* @return string
* @deprecated
*/
public function getFromRef();

/**
* @return string[]|null
*/
public function getFromRefs();
}
18 changes: 18 additions & 0 deletions src/Structure/ObjectItemTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,31 @@ public function setDocumentPath($path)
}

/**
* @see ObjectItemContract::getFromRef
* @deprecated use ObjectItemContract::getFromRefs
* @see ObjectItemContract::getFromRefs
* @todo remove
* @return string
*/
public function getFromRef()
{
return null === $this->__fromRef ? null : $this->__fromRef[0];
}

/**
* @see ObjectItemContract::getFromRef
* @return string
*/
public function getFromRefs()
{
return $this->__fromRef;
}

/**
* @see ObjectItemContract::setFromRef
* @param string $ref
* @return $this
*/
public function setFromRef($ref)
{
if (null === $this->__fromRef) {
Expand Down
22 changes: 22 additions & 0 deletions tests/src/Helper/DeepRefAnotherTitle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Swaggest\JsonSchema\Tests\Helper;


use Swaggest\JsonSchema\Constraint\Properties;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;

class DeepRefAnotherTitle extends ClassStructure
{
/**
* @param Properties|static $properties
* @param Schema $ownerSchema
*/
public static function setUpProperties($properties, Schema $ownerSchema)
{
$ownerSchema->setFromRef('http://json-schema.org/draft-04/schema#/properties/title');
$ownerSchema->setFromRef('#/definitions/anotherTitle');
}

}
25 changes: 25 additions & 0 deletions tests/src/Helper/DeepRefProperty.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Swaggest\JsonSchema\Tests\Helper;

use Swaggest\JsonSchema\Constraint\Properties;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;

class DeepRefProperty extends ClassStructure
{
/**
* @param Properties|static $properties
* @param Schema $ownerSchema
*/
public static function setUpProperties($properties, Schema $ownerSchema)
{
$ownerSchema->type = Schema::OBJECT;
$ownerSchema->setFromRef('#/definitions/lvlA');
$ownerSchema->setFromRef('#/definitions/lvlB');
$ownerSchema->setFromRef('#/definitions/lvlC');
$ownerSchema->setFromRef('#/definitions/lvlD');
}


}
37 changes: 37 additions & 0 deletions tests/src/Helper/DeepRefRoot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Swaggest\JsonSchema\Tests\Helper;


use Swaggest\JsonSchema\Constraint\Properties;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;

class DeepRefRoot extends ClassStructure
{
public $directTitle;

public $intermediateTitle;

public $anotherTitle;

public $prop;

/**
* @param Properties|static $properties
* @param Schema $ownerSchema
*/
public static function setUpProperties($properties, Schema $ownerSchema)
{
$properties->prop = DeepRefProperty::schema();

$properties->directTitle = new Schema();
$properties->directTitle->ref = 'http://json-schema.org/draft-04/schema#/properties/title';

$properties->intermediateTitle = DeepRefTitle::schema();

$properties->anotherTitle = DeepRefAnotherTitle::schema();

$ownerSchema->type = Schema::STRING;
}
}
21 changes: 21 additions & 0 deletions tests/src/Helper/DeepRefTitle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Swaggest\JsonSchema\Tests\Helper;


use Swaggest\JsonSchema\Constraint\Properties;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;

class DeepRefTitle extends ClassStructure
{
/**
* @param Properties|static $properties
* @param Schema $ownerSchema
*/
public static function setUpProperties($properties, Schema $ownerSchema)
{
$ownerSchema->setFromRef('http://json-schema.org/draft-04/schema#/properties/title');
$ownerSchema->setFromRef('#/definitions/title');
}
}
96 changes: 96 additions & 0 deletions tests/src/PHPUnit/ClassStructure/ExportSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Tests\Helper\DbId;
use Swaggest\JsonSchema\Tests\Helper\DeepRefRoot;

class ExportSchemaTest extends \PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -34,4 +35,99 @@ public function testSchemaExport()
$this->assertSame($expected, json_encode($schemaData, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));
}

public function testDeepRef()
{
$schema = DeepRefRoot::schema();
$schemaData = Schema::export($schema);

$expected = <<<'JSON'
{
"properties": {
"prop": {
"$ref": "#/definitions/lvlD"
},
"directTitle": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
},
"intermediateTitle": {
"$ref": "#/definitions/title"
},
"anotherTitle": {
"$ref": "#/definitions/anotherTitle"
}
},
"type": "string",
"definitions": {
"lvlA": {
"type": "object"
},
"lvlB": {
"$ref": "#/definitions/lvlA"
},
"lvlC": {
"$ref": "#/definitions/lvlB"
},
"lvlD": {
"$ref": "#/definitions/lvlC"
},
"title": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
},
"anotherTitle": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
}
}
}
JSON;

$this->assertSame($expected, json_encode($schemaData, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));


}

public function testDeepRefSchema()
{
$schemaJson = <<<'JSON'
{
"definitions": {
"lvl1": {
"$ref": "#/definitions/lvl2"
},
"lvl2": {
"$ref": "#/definitions/lvl3"
},
"lvl3": {
"$ref": "#/definitions/lvl4"
},
"lvl4": {
"type": "integer"
},
"title": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
},
"anotherTitle": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
}
},
"properties": {
"prop": {
"$ref": "#/definitions/lvl1"
},
"intermediateTitle": {
"$ref": "#/definitions/title"
},
"anotherTitle": {
"$ref": "#/definitions/anotherTitle"
}
},
"type": "object"
}
JSON;
$schemaData = json_decode($schemaJson);

$schema = Schema::import($schemaData);
$exported = Schema::export($schema);
$this->assertSame($schemaJson, json_encode($exported, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES));
}

}

0 comments on commit 98ffcb9

Please # to comment.