Skip to content

Commit 2d60104

Browse files
committed
Merge pull request #125 from MLKiiwy/#79-custom-identifier
#79 custom identifier
2 parents bd5e614 + 850262b commit 2d60104

28 files changed

+1787
-869
lines changed

Api/IriConverter.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Dunglas\ApiBundle\Api;
1313

14+
use Dunglas\ApiBundle\Mapping\AttributeMetadataInterface;
15+
use Dunglas\ApiBundle\Mapping\ClassMetadataFactory;
1416
use Dunglas\ApiBundle\Model\DataProviderInterface;
1517
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
1618
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
@@ -43,18 +45,24 @@ class IriConverter implements IriConverterInterface
4345
* @var \SplObjectStorage
4446
*/
4547
private $routeCache;
48+
/**
49+
* @var ClassMetadataFactory
50+
*/
51+
private $classMetadataFactory;
4652

4753
public function __construct(
4854
ResourceCollectionInterface $resourceCollection,
4955
DataProviderInterface $dataProvider,
5056
RouterInterface $router,
51-
PropertyAccessorInterface $propertyAccessor
57+
PropertyAccessorInterface $propertyAccessor,
58+
ClassMetadataFactory $classMetadataFactory
5259
) {
5360
$this->resourceCollection = $resourceCollection;
5461
$this->dataProvider = $dataProvider;
5562
$this->router = $router;
5663
$this->propertyAccessor = $propertyAccessor;
5764
$this->routeCache = new \SplObjectStorage();
65+
$this->classMetadataFactory = $classMetadataFactory;
5866
}
5967

6068
/**
@@ -85,9 +93,11 @@ public function getItemFromIri($iri, $fetchData = false)
8593
public function getIriFromItem($item, $referenceType = RouterInterface::ABSOLUTE_PATH)
8694
{
8795
if ($resource = $this->resourceCollection->getResourceForEntity($item)) {
96+
$identifier = $this->getIdentifierFromResource($resource);
97+
8898
return $this->router->generate(
8999
$this->getRouteName($resource, 'item'),
90-
['id' => $this->propertyAccessor->getValue($item, 'id')],
100+
['id' => $this->propertyAccessor->getValue($item, $identifier->getName())],
91101
$referenceType
92102
);
93103
}
@@ -134,4 +144,21 @@ private function getRouteName(ResourceInterface $resource, $prefix)
134144
}
135145
}
136146
}
147+
148+
/**
149+
* @param ResourceInterface $resource
150+
*
151+
* @return AttributeMetadataInterface
152+
*/
153+
private function getIdentifierFromResource(ResourceInterface $resource)
154+
{
155+
$classMetadata = $this->classMetadataFactory->getMetadataFor(
156+
$resource->getEntityClass(),
157+
$resource->getNormalizationGroups(),
158+
$resource->getDenormalizationGroups(),
159+
$resource->getValidationGroups()
160+
);
161+
162+
return $classMetadata->getIdentifier();
163+
}
137164
}

Doctrine/Orm/DataProvider.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ public function getCollection(ResourceInterface $resource, Request $request)
118118
}
119119
}
120120

121-
if (null !== $this->order) {
122-
$queryBuilder->addOrderBy('o.id', $this->order);
121+
$classMetaData = $manager->getClassMetadata($entityClass);
122+
$identifiers = $classMetaData->getIdentifier();
123+
124+
if (null !== $this->order && 1 === count($identifiers)) {
125+
$identifier = $identifiers[0];
126+
$queryBuilder->addOrderBy('o.'.$identifier, $this->order);
123127
}
124128

125129
return new Paginator(new DoctrineOrmPaginator($queryBuilder));

Hydra/ApiDocumentationBuilder.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ public function getApiDocumentation()
123123

124124
$properties = [];
125125
foreach ($classMetadata->getAttributes() as $attributeName => $attributeMetadata) {
126+
if ($attributeMetadata->isIdentifier() && !$attributeMetadata->isWritable()) {
127+
continue;
128+
}
129+
126130
if ($attributeMetadata->isNormalizationLink()) {
127131
$type = 'Hydra:Link';
128132
} else {
@@ -139,7 +143,7 @@ public function getApiDocumentation()
139143
],
140144
'hydra:title' => $attributeName,
141145
'hydra:required' => $attributeMetadata->isRequired(),
142-
'hydra:readable' => $attributeMetadata->isReadable(),
146+
'hydra:readable' => $attributeMetadata->isIdentifier() ? false : $attributeMetadata->isReadable(),
143147
'hydra:writable' => $attributeMetadata->isWritable(),
144148
];
145149

JsonLd/EventListener/ResourceContextBuilderListener.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public function onContextBuilder(ContextBuilderEvent $event)
6565
)->getAttributes();
6666

6767
foreach ($attributes as $attributeName => $attribute) {
68+
if ($attribute->isIdentifier()) {
69+
continue;
70+
}
6871
$convertedName = $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName;
6972

7073
if (!$id = $attribute->getIri()) {

JsonLd/Serializer/ItemNormalizer.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,10 @@ public function normalize($object, $format = null, array $context = [])
124124
$data['@type'] = ($iri = $classMetadata->getIri()) ? $iri : $resource->getShortName();
125125

126126
foreach ($attributesMetadata as $attributeMetadata) {
127-
$attributeName = $attributeMetadata->getName();
128-
129-
if ('id' === $attributeName || !$attributeMetadata->isReadable()) {
127+
if ($attributeMetadata->isIdentifier() || !$attributeMetadata->isReadable()) {
130128
continue;
131129
}
132-
130+
$attributeName = $attributeMetadata->getName();
133131
$attributeValue = $this->propertyAccessor->getValue($object, $attributeName);
134132

135133
if ($this->nameConverter) {

Mapping/AttributeMetadata.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
class AttributeMetadata implements AttributeMetadataInterface
2020
{
21+
const DEFAULT_IDENTIFIER_NAME = 'id';
22+
2123
/**
2224
* @var string
2325
*
@@ -90,13 +92,23 @@ class AttributeMetadata implements AttributeMetadataInterface
9092
* {@link getIri()} instead.
9193
*/
9294
public $iri;
95+
/**
96+
* @var bool
97+
*
98+
* @internal This property is public in order to reduce the size of the
99+
* class' serialized representation. Do not access it. Use
100+
* {@link isIdentifier()} instead.
101+
*/
102+
public $identifier;
93103

94104
/**
95-
* @param string $name
105+
* @param string $name
106+
* @param bool|null $identifier
96107
*/
97-
public function __construct($name)
108+
public function __construct($name, $identifier = null)
98109
{
99110
$this->name = $name;
111+
$this->identifier = ($identifier === null) ? $name === self::DEFAULT_IDENTIFIER_NAME : $identifier;
100112
}
101113

102114
/**
@@ -235,6 +247,22 @@ public function getIri()
235247
return $this->iri;
236248
}
237249

250+
/**
251+
* @return bool
252+
*/
253+
public function isIdentifier()
254+
{
255+
return $this->identifier;
256+
}
257+
258+
/**
259+
* @param bool $identifier
260+
*/
261+
public function setIdentifier($identifier)
262+
{
263+
$this->identifier = $identifier;
264+
}
265+
238266
/**
239267
* Returns the names of the properties that should be serialized.
240268
*
@@ -251,6 +279,7 @@ public function __sleep()
251279
'required',
252280
'link',
253281
'iri',
282+
'identifier',
254283
];
255284
}
256285
}

Mapping/AttributeMetadataInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,11 @@ public function setIri($iri);
136136
* @return string|null
137137
*/
138138
public function getIri();
139+
140+
/**
141+
* Is attribute the identifier of the class.
142+
*
143+
* @return bool
144+
*/
145+
public function isIdentifier();
139146
}

Mapping/ClassMetadata.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,20 @@ public function getIri()
105105
return $this->iri;
106106
}
107107

108+
/**
109+
* @return AttributeMetadataInterface
110+
*/
111+
public function getIdentifier()
112+
{
113+
foreach ($this->attributes as $attribute) {
114+
if ($attribute->isIdentifier()) {
115+
return $attribute;
116+
}
117+
}
118+
119+
return;
120+
}
121+
108122
/**
109123
* {@inheritdoc}
110124
*/

Mapping/ClassMetadataInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,11 @@ public function getAttributes();
7373
* @return \ReflectionClass
7474
*/
7575
public function getReflectionClass();
76+
77+
/**
78+
* Gets the attribute identifier of the class.
79+
*
80+
* @return AttributeMetadataInterface
81+
*/
82+
public function getIdentifier();
7683
}

0 commit comments

Comments
 (0)