Skip to content

Commit 2d8b8d3

Browse files
authored
Merge pull request #2 from swaggest/name-mapping
name mapping, updated tests and README
2 parents 634fb75 + c1cfd4c commit 2d8b8d3

File tree

15 files changed

+526
-73
lines changed

15 files changed

+526
-73
lines changed

README.md

Lines changed: 148 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ JSON
9292
/**
9393
* @property int $quantity PHPDoc defined dynamic properties will be validated on every set
9494
*/
95-
class Example extends ClassStructure
95+
class User extends ClassStructure
9696
{
9797
/* Native (public) properties will be validated only on import and export of structure data */
9898

@@ -102,30 +102,53 @@ class Example extends ClassStructure
102102
/** @var Order[] */
103103
public $orders;
104104

105+
/** @var UserInfo */
106+
public $info;
107+
105108
/**
106-
* Define your properties
107-
*
108109
* @param Properties|static $properties
109110
* @param Schema $ownerSchema
110111
*/
111112
public static function setUpProperties($properties, Schema $ownerSchema)
112113
{
114+
// Setup property schemas
113115
$properties->id = Schema::integer();
114116
$properties->name = Schema::string();
115117

118+
// You can embed structures to main level with nested schemas
119+
$properties->info = UserInfo::schema()->nested();
120+
121+
// Dynamic (phpdoc-defined) properties can be used as well
116122
$properties->quantity = Schema::integer();
117123
$properties->quantity->minimum = 0;
118124

125+
// Property can be any complex structure
119126
$properties->orders = Schema::create();
120127
$properties->orders->items = Order::schema();
121128

122129
$ownerSchema->required = array(self::names()->id);
123130
}
124131
}
125132

126-
/**
127-
*
128-
*/
133+
134+
class UserInfo extends ClassStructure {
135+
public $firstName;
136+
public $lastName;
137+
public $birthDay;
138+
139+
/**
140+
* @param Properties|static $properties
141+
* @param Schema $ownerSchema
142+
*/
143+
public static function setUpProperties($properties, Schema $ownerSchema)
144+
{
145+
$properties->firstName = Schema::string();
146+
$properties->lastName = Schema::string();
147+
$properties->birthDay = Schema::string();
148+
}
149+
}
150+
151+
129152
class Order extends ClassStructure
130153
{
131154
public $id;
@@ -139,7 +162,7 @@ class Order extends ClassStructure
139162
public static function setUpProperties($properties, Schema $ownerSchema)
140163
{
141164
$properties->id = Schema::integer();
142-
$properties->dateTime = Schema::string();
165+
$properties->dateTime = Schema::string()->meta(new FieldName('date_time'));
143166
$properties->dateTime->format = Schema::FORMAT_DATE_TIME;
144167
$properties->price = Schema::number();
145168

@@ -152,26 +175,134 @@ Validation of dynamic properties is performed on set,
152175
this can help to find source of invalid data at cost of
153176
some performance drop
154177
```php
155-
$example = new Example();
156-
$example->quantity = -1; // Exception: Value more than 0 expected, -1 received
178+
$user = new User();
179+
$user->quantity = -1; // Exception: Value more than 0 expected, -1 received
157180
```
158181

159182
Validation of native properties is performed only on import/export
160183
```php
161-
$example = new Example();
162-
$example->quantity = 10;
163-
Example::export($example); // Exception: Required property missing: id
184+
$user = new User();
185+
$user->quantity = 10;
186+
User::export($user); // Exception: Required property missing: id
164187
```
165188

166189
Error messages provide a path to invalid data
167190
```php
168-
$example = new Example();
169-
$example->id = 1;
170-
$example->name = 'John Doe';
191+
$user = new User();
192+
$user->id = 1;
193+
$user->name = 'John Doe';
171194

172195
$order = new Order();
173196
$order->dateTime = (new \DateTime())->format(DATE_RFC3339);
174-
$example->orders[] = $order;
197+
$user->orders[] = $order;
175198

176-
Example::export($example); // Exception: Required property missing: id at #->properties:orders->items[0]
199+
User::export($user); // Exception: Required property missing: id at #->properties:orders->items[0]
200+
```
201+
202+
#### Nested structures
203+
204+
Nested structures allow you to make composition: flatten several objects in one and separate back.
205+
206+
```php
207+
$user = new User();
208+
$user->id = 1;
209+
210+
$info = new UserInfo();
211+
$info->firstName = 'John';
212+
$info->lastName = 'Doe';
213+
$info->birthDay = '1970-01-01';
214+
$user->info = $info;
215+
216+
$json = <<<JSON
217+
{
218+
"id": 1,
219+
"firstName": "John",
220+
"lastName": "Doe",
221+
"birthDay": "1970-01-01"
222+
}
223+
JSON;
224+
$exported = User::export($user);
225+
$this->assertSame($json, json_encode($exported, JSON_PRETTY_PRINT));
226+
227+
$imported = User::import(json_decode($json));
228+
$this->assertSame('John', $imported->info->firstName);
229+
$this->assertSame('Doe', $imported->info->lastName);
230+
```
231+
232+
You can also use `\Swaggest\JsonSchema\Structure\Composition` to dynamically create schema compositions.
233+
This can be helpful to deal with results of database query on joined data.
234+
235+
```php
236+
$schema = new Composition(UserInfo::schema(), Order::schema());
237+
$json = <<<JSON
238+
{
239+
"id": 1,
240+
"firstName": "John",
241+
"lastName": "Doe",
242+
"price": 2.66
243+
}
244+
JSON;
245+
$object = $schema->import(json_decode($json));
246+
247+
// Get particular object with `pick` accessor
248+
$info = UserInfo::pick($object);
249+
$order = Order::pick($object);
250+
251+
// Data is imported objects of according classes
252+
$this->assertTrue($order instanceof Order);
253+
$this->assertTrue($info instanceof UserInfo);
254+
255+
$this->assertSame(1, $order->id);
256+
$this->assertSame('John', $info->firstName);
257+
$this->assertSame('Doe', $info->lastName);
258+
$this->assertSame(2.66, $order->price);
259+
```
260+
261+
#### Keys mapping
262+
263+
If property names of PHP objects should be different from raw data you
264+
can apply `\Swaggest\JsonSchema\PreProcessor\NameMapper` during processing.
265+
It takes `Swaggest\JsonSchema\Meta\FieldName` as source of raw name.
266+
267+
```php
268+
$properties->dateTime = Schema::string()->meta(new FieldName('date_time'));
269+
```
270+
271+
```php
272+
$mapper = new NameMapper();
273+
274+
$order = new Order();
275+
$order->id = 1;
276+
$order->dateTime = '2015-10-28T07:28:00Z';
277+
$exported = Order::export($order, $mapper);
278+
$json = <<<JSON
279+
{
280+
"id": 1,
281+
"date_time": "2015-10-28T07:28:00Z"
282+
}
283+
JSON;
284+
$this->assertSame($json, json_encode($exported, JSON_PRETTY_PRINT));
285+
286+
$imported = Order::import(json_decode($json), $mapper);
287+
$this->assertSame('2015-10-28T07:28:00Z', $imported->dateTime);
288+
```
289+
290+
You can create your own pre-processor implementing `Swaggest\JsonSchema\DataPreProcessor`.
291+
292+
#### Meta
293+
294+
`Meta` is a way to complement `Schema` with your own data. You can keep and retrieve it.
295+
296+
You can store it.
297+
```php
298+
$schema = new Schema();
299+
// Setting meta
300+
$schema->meta(new FieldName('my-value'));
301+
```
302+
303+
And get back.
304+
```php
305+
// Retrieving meta
306+
$myMeta = FieldName::get($schema);
307+
$this->assertSame('my-value', $myMeta->name);
177308
```

src/DataPreProcessor.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;
4+
5+
6+
interface DataPreProcessor
7+
{
8+
/**
9+
* @param $data mixed original data
10+
* @param Schema $schema
11+
* @param bool $import
12+
* @return mixed processed data
13+
*/
14+
public function process($data, Schema $schema, $import = true);
15+
}

src/MagicMap.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,36 @@ public function jsonSerialize()
5757
return (object)$this->__arrayOfData;
5858
}
5959

60+
private $__propertyToDataMap;
61+
public function setPropertyToDataMap($map)
62+
{
63+
$this->__propertyToDataMap = $map;
64+
return $this;
65+
}
66+
67+
public function getPropertyToDataMap()
68+
{
69+
return $this->__propertyToDataMap;
70+
}
71+
72+
private $__dataToPropertyMap;
73+
74+
/**
75+
* @return mixed
76+
*/
77+
public function getDataToPropertyMap()
78+
{
79+
return $this->__dataToPropertyMap;
80+
}
81+
82+
/**
83+
* @param mixed $_dataToPropertyMap
84+
* @return MagicMap
85+
*/
86+
public function setDataToPropertyMap($_dataToPropertyMap)
87+
{
88+
$this->__dataToPropertyMap = $_dataToPropertyMap;
89+
return $this;
90+
}
6091

6192
}

src/Meta.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ abstract class Meta
77
{
88
/**
99
* @param Schema $schema
10-
* @return null|static
10+
* @return static
1111
*/
1212
public static function get(Schema $schema)
1313
{

src/Meta/FieldName.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\Meta;
4+
5+
use Swaggest\JsonSchema\Meta;
6+
7+
class FieldName extends Meta
8+
{
9+
public $name;
10+
public function __construct($name)
11+
{
12+
$this->name = $name;
13+
}
14+
15+
}

src/PreProcessor/NameMapper.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Swaggest\JsonSchema\PreProcessor;
4+
5+
6+
use Swaggest\JsonSchema\DataPreProcessor;
7+
use Swaggest\JsonSchema\Meta\FieldName;
8+
use Swaggest\JsonSchema\Schema;
9+
10+
class NameMapper implements DataPreProcessor
11+
{
12+
public function process($data, Schema $schema, $import = true)
13+
{
14+
if ($schema->properties !== null && is_object($data)) {
15+
$result = new \stdClass();
16+
foreach ($schema->properties->toArray() as $propertyName => $property) {
17+
if ($fieldNameMeta = FieldName::get($property)) {
18+
$fieldName = $fieldNameMeta->name;
19+
} else {
20+
$fieldName = $propertyName;
21+
}
22+
23+
if ($import) {
24+
if (property_exists($data, $fieldName)) {
25+
$result->$propertyName = $data->$fieldName;
26+
}
27+
} else {
28+
if (property_exists($data, $propertyName)) {
29+
$result->$fieldName = $data->$propertyName;
30+
}
31+
}
32+
}
33+
return $result;
34+
}
35+
36+
return $data;
37+
}
38+
}

0 commit comments

Comments
 (0)