Skip to content

Commit b209041

Browse files
author
Nil Portugués
committed
v1.1 version. Class mapping
1 parent 0dc5cea commit b209041

File tree

8 files changed

+190
-24
lines changed

8 files changed

+190
-24
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"psr-4": {
2929
"NilPortugues\\Api\\Http\\": "src/Http/",
3030
"NilPortugues\\Api\\Mapping\\": "src/Mapping/",
31+
"NilPortugues\\Api\\Mappings\\": "src/Mappings/",
3132
"NilPortugues\\Api\\Transformer\\": "src/Transformer/"
3233
}
3334
},

src/Mapping/Mapper.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ public function __construct(array $mappings = null)
3333
{
3434
if (is_array($mappings)) {
3535
foreach ($mappings as $mappedClass) {
36-
$mapping = MappingFactory::fromArray($mappedClass);
36+
if (is_string($mappedClass) && class_exists($mappedClass, true)) {
37+
$mapping = MappingFactory::fromClass($mappedClass);
38+
} else {
39+
$mapping = MappingFactory::fromArray($mappedClass);
40+
}
3741

3842
if (false === empty($this->aliasMap[$mapping->getClassAlias()])) {
3943
throw new MappingException(

src/Mapping/MappingFactory.php

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,65 @@
1010
*/
1111
namespace NilPortugues\Api\Mapping;
1212

13+
use NilPortugues\Api\Mappings\ApiMapping;
14+
use NilPortugues\Api\Mappings\HalJsonMapping;
15+
use NilPortugues\Api\Mappings\JsonApiMapping;
1316
use ReflectionClass;
1417

1518
/**
1619
* Class MappingFactory.
1720
*/
1821
class MappingFactory
1922
{
23+
const CLASS_KEY = 'class';
24+
const ALIAS_KEY = 'alias';
25+
const ALIASED_PROPERTIES_KEY = 'aliased_properties';
26+
const HIDE_PROPERTIES_KEY = 'hide_properties';
27+
const ID_PROPERTIES_KEY = 'id_properties';
28+
const URLS_KEY = 'urls';
29+
const CURIES_KEY = 'curies';
30+
const RELATIONSHIPS_KEY = 'relationships';
31+
const SELF_KEY = 'self';
32+
33+
/**
34+
* @param string $className
35+
*
36+
* @return Mapping
37+
*
38+
* @since 2.0.0
39+
*/
40+
public static function fromClass($className)
41+
{
42+
/* @var ApiMapping|HalJsonMapping|JsonApiMapping $instance */
43+
$className = (string) $className;
44+
$instance = new $className();
45+
46+
if (!in_array(ApiMapping::class, class_implements($instance, true))) {
47+
throw new MappingException(
48+
sprintf('Class %s must implement %s.', get_class($instance), ApiMapping::class)
49+
);
50+
}
51+
52+
$mappedClass = [
53+
self::CLASS_KEY => $instance->getClass(),
54+
self::ALIAS_KEY => $instance->getAlias(),
55+
self::ALIASED_PROPERTIES_KEY => $instance->getAliasedProperties(),
56+
self::HIDE_PROPERTIES_KEY => $instance->getHideProperties(),
57+
self::ID_PROPERTIES_KEY => $instance->getIdProperties(),
58+
self::URLS_KEY => $instance->getUrls(),
59+
];
60+
61+
if (in_array(HalJsonMapping::class, class_implements($instance, true))) {
62+
$mappedClass[self::CURIES_KEY] = $instance->getCuries();
63+
}
64+
65+
if (in_array(JsonApiMapping::class, class_implements($instance, true))) {
66+
$mappedClass[self::RELATIONSHIPS_KEY] = $instance->getRelationships();
67+
}
68+
69+
return self::fromArray($mappedClass);
70+
}
71+
2072
/**
2173
* @var array
2274
*/
@@ -36,7 +88,7 @@ public static function fromArray(array &$mappedClass)
3688
$idProperties = self::getIdProperties($mappedClass);
3789

3890
$mapping = new Mapping($className, $resourceUrl, $idProperties);
39-
$mapping->setClassAlias((empty($mappedClass['alias'])) ? $className : $mappedClass['alias']);
91+
$mapping->setClassAlias((empty($mappedClass[self::ALIAS_KEY])) ? $className : $mappedClass[self::ALIAS_KEY]);
4092

4193
self::setAliasedProperties($mappedClass, $mapping, $className);
4294
self::setHideProperties($mappedClass, $mapping, $className);
@@ -60,13 +112,13 @@ public static function fromArray(array &$mappedClass)
60112
*/
61113
private static function getClass(array &$mappedClass)
62114
{
63-
if (empty($mappedClass['class'])) {
115+
if (empty($mappedClass[self::CLASS_KEY])) {
64116
throw new MappingException(
65117
'Could not find "class" property. This is required for class to be mapped'
66118
);
67119
}
68120

69-
return $mappedClass['class'];
121+
return $mappedClass[self::CLASS_KEY];
70122
}
71123

72124
/**
@@ -78,13 +130,13 @@ private static function getClass(array &$mappedClass)
78130
*/
79131
private static function getSelfUrl(array &$mappedClass)
80132
{
81-
if (empty($mappedClass['urls']['self'])) {
133+
if (empty($mappedClass[self::URLS_KEY][self::SELF_KEY])) {
82134
throw new MappingException(
83135
'Could not find "self" property under "urls". This is required in order to make the resource to be reachable.'
84136
);
85137
}
86138

87-
return $mappedClass['urls']['self'];
139+
return $mappedClass[self::URLS_KEY][self::SELF_KEY];
88140
}
89141

90142
/**
@@ -94,7 +146,7 @@ private static function getSelfUrl(array &$mappedClass)
94146
*/
95147
private static function getIdProperties(array &$mappedClass)
96148
{
97-
return (!empty($mappedClass['id_properties'])) ? $mappedClass['id_properties'] : [];
149+
return (!empty($mappedClass[self::ID_PROPERTIES_KEY])) ? $mappedClass[self::ID_PROPERTIES_KEY] : [];
98150
}
99151

100152
/**
@@ -106,8 +158,8 @@ private static function getIdProperties(array &$mappedClass)
106158
*/
107159
protected static function setAliasedProperties(array &$mappedClass, Mapping $mapping, $className)
108160
{
109-
if (false === empty($mappedClass['aliased_properties'])) {
110-
$mapping->setPropertyNameAliases($mappedClass['aliased_properties']);
161+
if (false === empty($mappedClass[self::ALIASED_PROPERTIES_KEY])) {
162+
$mapping->setPropertyNameAliases($mappedClass[self::ALIASED_PROPERTIES_KEY]);
111163
foreach (array_keys($mapping->getAliasedProperties()) as $propertyName) {
112164
if (false === in_array($propertyName, self::getClassProperties($className), true)) {
113165
throw new MappingException(
@@ -163,8 +215,8 @@ private static function getClassProperties($className)
163215
*/
164216
protected static function setHideProperties(array &$mappedClass, Mapping $mapping, $className)
165217
{
166-
if (false === empty($mappedClass['hide_properties'])) {
167-
$mapping->setHiddenProperties($mappedClass['hide_properties']);
218+
if (false === empty($mappedClass[self::HIDE_PROPERTIES_KEY])) {
219+
$mapping->setHiddenProperties($mappedClass[self::HIDE_PROPERTIES_KEY]);
168220
foreach ($mapping->getHiddenProperties() as $propertyName) {
169221
if (false === in_array($propertyName, self::getClassProperties($className), true)) {
170222
throw new MappingException(
@@ -188,9 +240,9 @@ protected static function setHideProperties(array &$mappedClass, Mapping $mappin
188240
*/
189241
protected static function setRelationships(array &$mappedClass, Mapping $mapping, $className)
190242
{
191-
if (!empty($mappedClass['relationships'])) {
192-
foreach ($mappedClass['relationships'] as $propertyName => $urls) {
193-
if (false === in_array($propertyName, self::getClassProperties($className), true)) {
243+
if (!empty($mappedClass[self::RELATIONSHIPS_KEY])) {
244+
foreach ($mappedClass[self::RELATIONSHIPS_KEY] as $propertyName => $urls) {
245+
if (false === in_array($propertyName, self::getClassProperties($className))) {
194246
throw new MappingException(
195247
sprintf(
196248
'Could not find property %s in class %s because it does not exist.',
@@ -211,8 +263,8 @@ protected static function setRelationships(array &$mappedClass, Mapping $mapping
211263
*/
212264
protected static function setCuries(array &$mappedClass, Mapping $mapping)
213265
{
214-
if (false === empty($mappedClass['curies'])) {
215-
$mapping->setCuries($mappedClass['curies']);
266+
if (false === empty($mappedClass[self::CURIES_KEY])) {
267+
$mapping->setCuries($mappedClass[self::CURIES_KEY]);
216268
}
217269
}
218270

@@ -223,10 +275,10 @@ protected static function setCuries(array &$mappedClass, Mapping $mapping)
223275
*/
224276
private static function getOtherUrls(array $mappedClass)
225277
{
226-
if (!empty($mappedClass['urls']['self'])) {
227-
unset($mappedClass['urls']['self']);
278+
if (!empty($mappedClass[self::URLS_KEY][self::SELF_KEY])) {
279+
unset($mappedClass[self::URLS_KEY][self::SELF_KEY]);
228280
}
229281

230-
return $mappedClass['urls'];
282+
return $mappedClass[self::URLS_KEY];
231283
}
232284
}

src/Mapping/ClassMapping/ApiMappingInterface.php renamed to src/Mappings/ApiMapping.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22

3-
namespace NilPortugues\Api\Mapping\ClassMapping;
3+
namespace NilPortugues\Api\Mappings;
44

5-
interface ApiMappingInterface
5+
interface ApiMapping
66
{
77
/**
88
* Returns a string with the full class name, including namespace.

src/Mapping/ClassMapping/HalJsonMapping.php renamed to src/Mappings/HalJsonMapping.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22

3-
namespace NilPortugues\Api\Mapping\ClassMapping;
3+
namespace NilPortugues\Api\Mappings;
44

5-
interface HalJsonMapping extends ApiMappingInterface
5+
interface HalJsonMapping extends ApiMapping
66
{
77
/**
88
* Returns an array of curies.

src/Mapping/ClassMapping/JsonApiMapping.php renamed to src/Mappings/JsonApiMapping.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace NilPortugues\Api\Mapping\ClassMapping;
3+
namespace NilPortugues\Api\Mappings;
44

55
interface JsonApiMapping
66
{

tests/Dummy/PostApiMapping.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace NilPortugues\Tests\Api\Dummy;
4+
5+
use NilPortugues\Api\Mappings\ApiMapping;
6+
use NilPortugues\Api\Mappings\HalJsonMapping;
7+
use NilPortugues\Api\Mappings\JsonApiMapping;
8+
use NilPortugues\Tests\Api\Dummy\ComplexObject\Post;
9+
10+
class PostApiMapping implements ApiMapping, JsonApiMapping, HalJsonMapping
11+
{
12+
/**
13+
* {@inheritdoc}
14+
*/
15+
public function getClass()
16+
{
17+
return Post::class;
18+
}
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
public function getAlias()
24+
{
25+
return 'Message';
26+
}
27+
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
public function getAliasedProperties()
32+
{
33+
return [
34+
'title' => 'headline',
35+
'content' => 'body',
36+
];
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function getHideProperties()
43+
{
44+
return [
45+
'comments',
46+
];
47+
}
48+
49+
/**
50+
* {@inheritdoc}
51+
*/
52+
public function getIdProperties()
53+
{
54+
return [
55+
'postId',
56+
];
57+
}
58+
59+
/**
60+
* {@inheritdoc}
61+
*/
62+
public function getUrls()
63+
{
64+
return [
65+
'self' => 'http://example.com/posts/{postId}',
66+
];
67+
}
68+
69+
/**
70+
* Returns an array of curies.
71+
*
72+
* @return array
73+
*/
74+
public function getCuries()
75+
{
76+
return [
77+
'name' => 'example',
78+
'href' => 'http://example.com/docs/rels/{rel}',
79+
];
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
public function getRelationships()
86+
{
87+
return [
88+
'author' => [
89+
'related' => 'http://example.com/posts/{postId}/author',
90+
'self' => 'http://example.com/posts/{postId}/relationships/author',
91+
],
92+
];
93+
}
94+
}

tests/Mapping/MappingFactoryTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,24 @@
1313
use NilPortugues\Api\Mapping\MappingException;
1414
use NilPortugues\Api\Mapping\MappingFactory;
1515
use NilPortugues\Tests\Api\Dummy\ComplexObject\Post;
16+
use NilPortugues\Tests\Api\Dummy\PostApiMapping;
1617

1718
class MappingFactoryTest extends \PHPUnit_Framework_TestCase
1819
{
20+
public function testItCanBuildMappingsFromClass()
21+
{
22+
$mapping = MappingFactory::fromClass(PostApiMapping::class);
23+
24+
$this->assertEquals(Post::class, $mapping->getClassName());
25+
$this->assertEquals('message', $mapping->getClassAlias());
26+
$this->assertEquals(['title' => 'headline', 'content' => 'body'], $mapping->getAliasedProperties());
27+
$this->assertEquals(['comments'], $mapping->getHiddenProperties());
28+
$this->assertEquals(['postId'], $mapping->getIdProperties());
29+
$this->assertEquals('http://example.com/posts/{postId}', $mapping->getResourceUrl());
30+
$this->assertEquals('http://example.com/posts/{postId}/author', $mapping->getRelatedUrl('author'));
31+
$this->assertEquals('http://example.com/posts/{postId}/relationships/author', $mapping->getRelationshipSelfUrl('author'));
32+
}
33+
1934
public function testItCanBuildMappingsFromArray()
2035
{
2136
$mappedClass = [

0 commit comments

Comments
 (0)