Skip to content

Commit 6a4c01e

Browse files
committed
aw yeah!
1 parent 46fd09a commit 6a4c01e

File tree

10 files changed

+179
-30
lines changed

10 files changed

+179
-30
lines changed

src/Constraint/Properties.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Swaggest\JsonSchema\MagicMap;
77
use Swaggest\JsonSchema\Schema;
88
use Swaggest\JsonSchema\Structure\Egg;
9+
use Swaggest\JsonSchema\Structure\Nested;
910

1011
/**
1112
* @method Schema __get($key)
@@ -17,6 +18,10 @@ class Properties extends MagicMap implements Constraint
1718

1819
public function __set($name, $column)
1920
{
21+
if ($column instanceof Nested) {
22+
$this->addNested($column->schema, $name);
23+
return $this;
24+
}
2025
return parent::__set($name, $column);
2126
}
2227

@@ -42,17 +47,15 @@ public function setAdditionalProperties(Schema $additionalProperties = null)
4247
/** @var Egg[] */
4348
private $nestedProperties = array();
4449

45-
public function addNested(Schema $nested, $name = null)
50+
/** @var Schema[] */
51+
public $nestedPropertyNames = array();
52+
53+
protected function addNested(Schema $nested, $name)
4654
{
4755
if (null === $nested->properties) {
4856
throw new Exception('Schema with properties required', Exception::PROPERTIES_REQUIRED);
4957
}
50-
if (null === $name) {
51-
$name = $nested->objectItemClass;
52-
}
53-
if (null === $name) {
54-
throw new Exception('Undefined nested name', Exception::UNDEFINED_NESTED_NAME);
55-
}
58+
$this->nestedPropertyNames[$name] = $name;
5659
foreach ($nested->properties->toArray() as $propertyName => $property) {
5760
$this->nestedProperties[$propertyName] = new Egg($nested, $name, $property);
5861
}

src/Schema.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ private function process($data, $import = true, $path = '#')
270270
if ($result->__validateOnSet) {
271271
$result->__validateOnSet = false;
272272
/** @noinspection PhpUnusedLocalVariableInspection */
273-
$validateOnSetHandler = new ScopeExit(function()use($result){
273+
$validateOnSetHandler = new ScopeExit(function () use ($result) {
274274
$result->__validateOnSet = true;
275275
});
276276
}
@@ -342,7 +342,7 @@ private function process($data, $import = true, $path = '#')
342342
}
343343
}
344344

345-
if ($nestedEgg) {
345+
if ($nestedEgg && $import) {
346346
$result->setNestedProperty($key, $value, $nestedEgg);
347347
} else {
348348
$result->$key = $value;

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+
}

src/Structure/ClassStructure.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
use Swaggest\JsonSchema\Constraint\Properties;
66
use Swaggest\JsonSchema\Constraint\Type;
77
use Swaggest\JsonSchema\NameMirror;
8-
use Swaggest\JsonSchema\Schema;
98

109
abstract class ClassStructure extends ObjectItem implements ClassStructureContract
1110
{
1211
/**
13-
* @return Schema
12+
* @return ClassSchema
1413
*/
1514
public static function schema()
1615
{
@@ -19,7 +18,7 @@ public static function schema()
1918
$schema = &$schemas[$className];
2019

2120
if (null === $schema) {
22-
$schema = new Schema();
21+
$schema = new ClassSchema();
2322
$schema->type = new Type(Type::OBJECT);
2423
$properties = new Properties();
2524
$schema->properties = $properties;
@@ -50,6 +49,19 @@ public static function export($data)
5049
return static::schema()->export($data);
5150
}
5251

52+
/**
53+
* @param ObjectItem $objectItem
54+
* @return static
55+
*/
56+
public static function pick(ObjectItem $objectItem)
57+
{
58+
$className = get_called_class();
59+
if (isset($objectItem->__nestedObjects[$className])) {
60+
return $objectItem->__nestedObjects[$className];
61+
}
62+
return null;
63+
}
64+
5365
/**
5466
* @return static
5567
*/
@@ -72,7 +84,13 @@ public function jsonSerialize() // todo process nested structures here
7284
$result->$name = $value;
7385
}
7486
}
75-
// foreach ($properties->addNested())
87+
foreach ($properties->nestedPropertyNames as $name) {
88+
/** @var ObjectItem $nested */
89+
$nested = $this->$name;
90+
foreach ((array)$nested->jsonSerialize() as $key => $value) {
91+
$result->$key = $value;
92+
}
93+
}
7694
} else {
7795
$result = parent::jsonSerialize();
7896
}

src/Structure/Composition.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema\Structure;
4+
5+
use Swaggest\JsonSchema\Constraint\Properties;
6+
use Swaggest\JsonSchema\Constraint\Type;
7+
use Swaggest\JsonSchema\Schema;
8+
9+
/**
10+
* @todo think of anyOf, allOf, oneOf
11+
*/
12+
class Composition extends Schema
13+
{
14+
/**
15+
* @param Schema... $schema
16+
*/
17+
public function __construct()
18+
{
19+
$this->type = new Type(Type::OBJECT);
20+
$properties = new Properties();
21+
$this->properties = $properties;
22+
23+
foreach (func_get_args() as $arg) {
24+
if ($arg instanceof ClassSchema) {
25+
$properties->__set($arg->objectItemClass, $arg->nested());
26+
}
27+
}
28+
}
29+
30+
}

src/Structure/Nested.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+
use Swaggest\JsonSchema\Schema;
6+
7+
class Nested
8+
{
9+
/** @var Schema */
10+
public $schema;
11+
public function __construct(Schema $schema)
12+
{
13+
$this->schema = $schema;
14+
}
15+
}

src/Structure/ObjectItem.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@
44

55

66
use Swaggest\JsonSchema\MagicMap;
7+
use Swaggest\JsonSchema\Schema;
78

89
class ObjectItem extends MagicMap
910
{
11+
/** @var ObjectItem[] */
1012
protected $__nestedObjects;
1113

1214
public function setNestedProperty($propertyName, $value, Egg $nestedEgg)
1315
{
14-
$nested = &$this->__nestedObjects[$nestedEgg->name];
16+
$nestedName = $nestedEgg->name;
17+
$nested = &$this->__nestedObjects[$nestedName];
1518
if (null === $nested) {
1619
$nested = $nestedEgg->classSchema->makeObjectItem();
20+
$this->__nestedObjects[$nestedName] = $nested;
21+
if ($nestedName !== $nestedEgg->classSchema->objectItemClass) {
22+
$this->$nestedName = $nested;
23+
}
1724
}
1825
$nested->$propertyName = $value;
19-
}
20-
21-
public function getNested($name)
22-
{
23-
if (isset($this->__nestedObjects[$name])) {
24-
return $this->__nestedObjects[$name];
25-
}
26-
return null;
26+
$this->__arrayOfData[$propertyName] = &$nested->$propertyName;
2727
}
2828

2929
protected $__additionalPropertyNames;
@@ -63,6 +63,13 @@ public function getPatternPropertyNames($pattern)
6363
public function jsonSerialize()
6464
{
6565
if ($this->__nestedObjects) {
66+
$result = $this->__arrayOfData;
67+
foreach ($this->__nestedObjects as $object) {
68+
foreach ($object->__arrayOfData as $key => $value) {
69+
$result[$key] = $value;
70+
}
71+
}
72+
return (object)$result;
6673
} else {
6774
return (object)$this->__arrayOfData;
6875
}

tests/src/Helper/NestedStructure.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99

1010
/**
1111
* @property $ownMagicInt
12+
* @method static|SampleStructure import($data)
1213
*/
1314
class NestedStructure extends ClassStructure
1415
{
1516
public $ownString;
17+
/** @var SampleStructure */
18+
public $sampleNested;
1619

1720
/**
1821
* @param Properties|static $properties
@@ -22,7 +25,6 @@ public static function setUpProperties($properties, Schema $ownerSchema)
2225
{
2326
$properties->ownMagicInt = Schema::integer();
2427
$properties->ownString = Schema::string();
25-
26-
$properties->addNested(SampleStructure::schema());
28+
$properties->sampleNested = SampleStructure::schema()->nested();
2729
}
2830
}

tests/src/Helper/SampleStructure.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
use Swaggest\JsonSchema\Structure\ClassStructure;
77

88
/**
9-
* @property $propOne
10-
* @property $propTwo
9+
* @property string $propOne
10+
* @property int $propTwo
1111
* @property $recursion
1212
*/
1313
class SampleStructure extends ClassStructure

tests/src/PHPUnit/ClassStructure/NestedTest.php

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,84 @@
33
namespace Swaggest\JsonSchema\Tests\PHPUnit\ClassStructure;
44

55

6+
use Swaggest\JsonSchema\Structure\Composition;
7+
use Swaggest\JsonSchema\Tests\Helper\LevelThreeClass;
68
use Swaggest\JsonSchema\Tests\Helper\NestedStructure;
79
use Swaggest\JsonSchema\Tests\Helper\SampleStructure;
810

911
class NestedTest extends \PHPUnit_Framework_TestCase
1012
{
1113
public function testClassStructure()
1214
{
13-
$schema = NestedStructure::schema();
1415
$data = json_decode(<<<JSON
1516
{
1617
"ownString": "aaa",
1718
"ownMagicInt": 1,
18-
"native": true
19+
"native": true,
20+
"propOne": "bbb"
1921
}
2022
JSON
21-
);
23+
);
24+
$object = NestedStructure::import($data);
25+
$this->assertSame('aaa', $object->ownString);
26+
$this->assertSame(true, $object->sampleNested->native);
27+
$this->assertSame('bbb', $object->sampleNested->propOne);
28+
29+
$data2 = NestedStructure::export($object);
30+
$this->assertEquals((array)$data, (array)$data2);
31+
32+
$object->sampleNested->propOne = 'ccc';
33+
$this->assertSame('ccc', $object->propOne);
34+
}
35+
36+
37+
public function testDynamic()
38+
{
39+
$schema = new Composition(SampleStructure::schema(), LevelThreeClass::schema());
40+
41+
$data = json_decode(<<<JSON
42+
{
43+
"ownString": "aaa",
44+
"ownMagicInt": 1,
45+
"native": true,
46+
"propOne": "bbb",
47+
"level3": 3
48+
}
49+
JSON
50+
);
51+
2252
$object = $schema->import($data);
53+
2354
$this->assertSame('aaa', $object->ownString);
24-
$this->assertSame(true, $object->getNested(SampleStructure::class)->native);
55+
$this->assertSame(1, $object->ownMagicInt);
56+
$this->assertSame(3, $object->level3); // flat accessor
57+
$this->assertSame(true, $object->native);
58+
59+
$sample = SampleStructure::pick($object);
60+
$l3 = LevelThreeClass::pick($object);
61+
62+
$this->assertSame('bbb', $sample->propOne);
63+
$this->assertSame(true, $sample->native);
64+
65+
$this->assertSame(3, $l3->level3);
66+
67+
$l3->level3 = 2;
68+
$this->assertSame(2, $object->level3); // flat accessor
69+
70+
$object->level3 = 5;
71+
$this->assertSame(5, $l3->level3);
72+
73+
$sample->propTwo = 8;
74+
75+
$data2 = $schema->export($object);
76+
$this->assertEquals(array(
77+
'ownString' => 'aaa',
78+
'ownMagicInt' => 1,
79+
'native' => true,
80+
'propOne' => 'bbb',
81+
'level3' => 5,
82+
'propTwo' => 8,
83+
), (array)$data2);
2584
}
2685

2786
}

0 commit comments

Comments
 (0)