Skip to content

Commit 634fb75

Browse files
authored
Merge pull request #1 from swaggest/nested-schema
Nested schema
2 parents 246773e + 034829c commit 634fb75

18 files changed

+459
-111
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ script:
3232
after_script:
3333
- wget https://scrutinizer-ci.com/ocular.phar
3434
- php ocular.phar code-coverage:upload --format=php-clover build/logs/coverage.clover
35-
- if [[ $(phpenv version-name) =~ 7.0 ]] ; then php vendor/bin/coveralls -v; fi
36-
- if [[ $(phpenv version-name) =~ 7.0 ]] ; then ./vendor/bin/test-reporter; fi
35+
- if [[ $(phpenv version-name) =~ 7.1 ]] ; then php vendor/bin/coveralls -v; fi
36+
- if [[ $(phpenv version-name) =~ 7.1 ]] ; then ./vendor/bin/test-reporter; fi

src/Constraint/Properties.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,26 @@
22

33
namespace Swaggest\JsonSchema\Constraint;
44

5+
use Swaggest\JsonSchema\Exception;
56
use Swaggest\JsonSchema\MagicMap;
67
use Swaggest\JsonSchema\Schema;
8+
use Swaggest\JsonSchema\Structure\Egg;
9+
use Swaggest\JsonSchema\Structure\Nested;
710

811
/**
912
* @method Schema __get($key)
1013
*/
1114
class Properties extends MagicMap implements Constraint
1215
{
1316
/** @var Schema[] */
14-
protected $_arrayOfData = array();
17+
protected $__arrayOfData = array();
1518

1619
public function __set($name, $column)
1720
{
21+
if ($column instanceof Nested) {
22+
$this->addNested($column->schema, $name);
23+
return $this;
24+
}
1825
return parent::__set($name, $column);
1926
}
2027

@@ -35,4 +42,31 @@ public function setAdditionalProperties(Schema $additionalProperties = null)
3542
$this->additionalProperties = $additionalProperties;
3643
return $this;
3744
}
45+
46+
47+
/** @var Egg[] */
48+
private $nestedProperties = array();
49+
50+
/** @var Schema[] */
51+
public $nestedPropertyNames = array();
52+
53+
protected function addNested(Schema $nested, $name)
54+
{
55+
if (null === $nested->properties) {
56+
throw new Exception('Schema with properties required', Exception::PROPERTIES_REQUIRED);
57+
}
58+
$this->nestedPropertyNames[$name] = $name;
59+
foreach ($nested->properties->toArray() as $propertyName => $property) {
60+
$this->nestedProperties[$propertyName] = new Egg($nested, $name, $property);
61+
}
62+
return $this;
63+
}
64+
65+
/**
66+
* @return Egg[]
67+
*/
68+
public function getNestedProperties()
69+
{
70+
return $this->nestedProperties;
71+
}
3872
}

src/Exception.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema;
4+
5+
6+
class Exception extends \Exception
7+
{
8+
const PROPERTIES_REQUIRED = 1;
9+
const UNDEFINED_NESTED_NAME = 2;
10+
11+
}

src/InvalidValue.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Swaggest\JsonSchema;
44

5-
class InvalidValue extends \Exception
5+
class InvalidValue extends Exception
66
{
77
public function addPath($path)
88
{

src/MagicMap.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44

55
class MagicMap implements \ArrayAccess, \JsonSerializable
66
{
7-
protected $_arrayOfData = array();
7+
protected $__arrayOfData = array();
88

99
public function __set($name, $column)
1010
{
11-
$this->_arrayOfData[$name] = $column;
11+
$this->__arrayOfData[$name] = $column;
1212
return $this;
1313
}
1414

1515
public function &__get($name)
1616
{
17-
if (isset($this->_arrayOfData[$name])) {
18-
return $this->_arrayOfData[$name];
17+
if (isset($this->__arrayOfData[$name])) {
18+
return $this->__arrayOfData[$name];
1919
} else {
2020
$tmp = null;
2121
return $tmp;
@@ -24,13 +24,13 @@ public function &__get($name)
2424

2525
public function offsetExists($offset)
2626
{
27-
return array_key_exists($offset, $this->_arrayOfData);
27+
return array_key_exists($offset, $this->__arrayOfData);
2828
}
2929

3030
public function &offsetGet($offset)
3131
{
32-
if (isset($this->_arrayOfData[$offset])) {
33-
return $this->_arrayOfData[$offset];
32+
if (isset($this->__arrayOfData[$offset])) {
33+
return $this->__arrayOfData[$offset];
3434
} else {
3535
$tmp = null;
3636
return $tmp;
@@ -44,17 +44,17 @@ public function offsetSet($offset, $value)
4444

4545
public function offsetUnset($offset)
4646
{
47-
unset($this->_arrayOfData[$offset]);
47+
unset($this->__arrayOfData[$offset]);
4848
}
4949

5050
public function &toArray()
5151
{
52-
return $this->_arrayOfData;
52+
return $this->__arrayOfData;
5353
}
5454

5555
public function jsonSerialize()
5656
{
57-
return (object)$this->_arrayOfData;
57+
return (object)$this->__arrayOfData;
5858
}
5959

6060

src/Meta.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema;
4+
5+
6+
abstract class Meta
7+
{
8+
/**
9+
* @param Schema $schema
10+
* @return null|static
11+
*/
12+
public static function get(Schema $schema)
13+
{
14+
return $schema->getMeta(get_called_class());
15+
}
16+
}

src/README.md

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/Schema.php

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Swaggest\JsonSchema\Exception\StringException;
1717
use Swaggest\JsonSchema\Exception\TypeException;
1818
use Swaggest\JsonSchema\Structure\ClassStructure;
19+
use Swaggest\JsonSchema\Structure\Egg;
1920
use Swaggest\JsonSchema\Structure\ObjectItem;
2021

2122
class Schema extends MagicMap
@@ -126,7 +127,7 @@ private function process($data, $import = true, $path = '#')
126127
if ($this->enum !== null) {
127128
$enumOk = false;
128129
foreach ($this->enum as $item) {
129-
if ($item === $data) {
130+
if ($item === $data) { // todo support complex structures here
130131
$enumOk = true;
131132
break;
132133
}
@@ -263,17 +264,13 @@ private function process($data, $import = true, $path = '#')
263264
}
264265

265266
if ($import && !$result instanceof ObjectItem) {
266-
if (null === $this->objectItemClass) {
267-
$result = new ObjectItem();
268-
} else {
269-
$result = new $this->objectItemClass;
270-
}
267+
$result = $this->makeObjectItem();
271268

272269
if ($result instanceof ClassStructure) {
273270
if ($result->__validateOnSet) {
274271
$result->__validateOnSet = false;
275272
/** @noinspection PhpUnusedLocalVariableInspection */
276-
$validateOnSetHandler = new ScopeExit(function()use($result){
273+
$validateOnSetHandler = new ScopeExit(function () use ($result) {
277274
$result->__validateOnSet = true;
278275
});
279276
}
@@ -282,7 +279,8 @@ private function process($data, $import = true, $path = '#')
282279

283280
if ($this->properties !== null) {
284281
/** @var Schema[] $properties */
285-
$properties = &$this->properties->toArray();
282+
$properties = &$this->properties->toArray(); // TODO check performance of pointer
283+
$nestedProperties = $this->properties->getNestedProperties();
286284
}
287285

288286
$array = (array)$data;
@@ -301,7 +299,8 @@ private function process($data, $import = true, $path = '#')
301299
} else {
302300
foreach ($dependencies as $item) {
303301
if (!property_exists($data, $item)) {
304-
$this->fail(new ObjectException('Dependency property missing: ' . $item, ObjectException::DEPENDENCY_MISSING), $path);
302+
$this->fail(new ObjectException('Dependency property missing: ' . $item,
303+
ObjectException::DEPENDENCY_MISSING), $path);
305304
}
306305
}
307306
}
@@ -312,11 +311,22 @@ private function process($data, $import = true, $path = '#')
312311
$value = $properties[$key]->process($value, $import, $path . '->properties:' . $key);
313312
}
314313

314+
/** @var Egg $nestedEgg */
315+
$nestedEgg = null;
316+
if (!$found && isset($nestedProperties[$key])) {
317+
$found = true;
318+
$nestedEgg = $nestedProperties[$key];
319+
$value = $nestedEgg->propertySchema->process($value, $import, $path . '->nestedProperties:' . $key);
320+
}
321+
315322
if ($this->patternProperties !== null) {
316323
foreach ($this->patternProperties as $pattern => $propertySchema) {
317324
if (preg_match($pattern, $key)) {
318325
$found = true;
319326
$value = $propertySchema->process($value, $import, $path . '->patternProperties:' . $pattern);
327+
if ($import) {
328+
$result->addPatternPropertyName($pattern, $key);
329+
}
320330
//break; // todo manage multiple import data properly (pattern accessor)
321331
}
322332
}
@@ -327,8 +337,17 @@ private function process($data, $import = true, $path = '#')
327337
}
328338

329339
$value = $this->additionalProperties->process($value, $import, $path . '->additionalProperties');
340+
if ($import) {
341+
$result->addAdditionalPropertyName($key);
342+
}
343+
}
344+
345+
if ($nestedEgg && $import) {
346+
$result->setNestedProperty($key, $value, $nestedEgg);
347+
} else {
348+
$result->$key = $value;
330349
}
331-
$result->$key = $value;
350+
332351
}
333352

334353
}
@@ -455,4 +474,31 @@ public function setProperty($name, Schema $schema)
455474
return $this;
456475
}
457476

477+
/** @var Meta[] */
478+
private $metaItems = array();
479+
public function meta(Meta $meta)
480+
{
481+
$this->metaItems[get_class($meta)] = $meta;
482+
return $this;
483+
}
484+
485+
public function getMeta($className)
486+
{
487+
if (isset($this->metaItems[$className])) {
488+
return $this->metaItems[$className];
489+
}
490+
return null;
491+
}
492+
493+
/**
494+
* @return ObjectItem
495+
*/
496+
public function makeObjectItem()
497+
{
498+
if (null === $this->objectItemClass) {
499+
return new ObjectItem();
500+
} else {
501+
return new $this->objectItemClass;
502+
}
503+
}
458504
}

src/Structure/ClassSchema.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema\Structure;
4+
5+
6+
use Swaggest\JsonSchema\Schema;
7+
8+
class ClassSchema extends Schema
9+
{
10+
public function nested()
11+
{
12+
return new Nested($this);
13+
}
14+
15+
}

0 commit comments

Comments
 (0)