Skip to content

Commit a5dc795

Browse files
authored
Merge pull request #1520 from MoltenCoreIO/subresource_depth
Subresource maxDepth
2 parents babe924 + 03439d4 commit a5dc795

File tree

8 files changed

+78
-6
lines changed

8 files changed

+78
-6
lines changed

src/Annotation/ApiSubresource.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@
2323
*/
2424
final class ApiSubresource
2525
{
26+
/**
27+
* @var int
28+
*/
29+
public $maxDepth;
2630
}

src/Metadata/Property/Factory/AnnotationSubresourceMetadataFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ private function updateMetadata(ApiSubresource $annotation, PropertyMetadata $pr
8282
$type = $propertyMetadata->getType();
8383
$isCollection = $type->isCollection();
8484
$resourceClass = $isCollection ? $type->getCollectionValueType()->getClassName() : $type->getClassName();
85+
$maxDepth = $annotation->maxDepth;
8586

86-
return $propertyMetadata->withSubresource(new SubresourceMetadata($resourceClass, $isCollection));
87+
return $propertyMetadata->withSubresource(new SubresourceMetadata($resourceClass, $isCollection, $maxDepth));
8788
}
8889
}

src/Metadata/Property/SubresourceMetadata.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ final class SubresourceMetadata
2222
{
2323
private $resourceClass;
2424
private $collection;
25+
private $maxDepth;
2526

26-
public function __construct(string $resourceClass, bool $collection = false)
27+
public function __construct(string $resourceClass, bool $collection = false, int $maxDepth = null)
2728
{
2829
$this->resourceClass = $resourceClass;
2930
$this->collection = $collection;
31+
$this->maxDepth = $maxDepth;
3032
}
3133

3234
public function getResourceClass(): string
@@ -54,4 +56,12 @@ public function withCollection(bool $collection): self
5456

5557
return $metadata;
5658
}
59+
60+
/**
61+
* @return int|null
62+
*/
63+
public function getMaxDepth()
64+
{
65+
return $this->maxDepth;
66+
}
5767
}

src/Metadata/schema/metadata.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<xsd:complexType name="subresource" mixed="true">
9595
<xsd:attribute type="xsd:boolean" name="collection"/>
9696
<xsd:attribute type="xsd:string" name="resourceClass"/>
97+
<xsd:attribute type="xsd:integer" name="maxDepth"/>
9798
</xsd:complexType>
9899

99100
<xsd:complexType name="property">

src/Operation/Factory/SubresourceOperationFactory.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ public function create(string $resourceClass): array
6060
* @param string $rootResourceClass null on the first iteration, it then keeps track of the origin resource class
6161
* @param array $parentOperation the previous call operation
6262
* @param array $visited
63+
* @param int $depth the number of visited
64+
* @param int $maxDepth
6365
*/
64-
private function computeSubresourceOperations(string $resourceClass, array &$tree, string $rootResourceClass = null, array $parentOperation = null, array $visited = [])
66+
private function computeSubresourceOperations(string $resourceClass, array &$tree, string $rootResourceClass = null, array $parentOperation = null, array $visited = [], int $depth = 0, int $maxDepth = null)
6567
{
6668
if (null === $rootResourceClass) {
6769
$rootResourceClass = $resourceClass;
@@ -79,6 +81,15 @@ private function computeSubresourceOperations(string $resourceClass, array &$tre
7981
$subresourceMetadata = $this->resourceMetadataFactory->create($subresourceClass);
8082

8183
$visiting = "$resourceClass $property $subresourceClass";
84+
85+
// Handle maxDepth
86+
if ($rootResourceClass === $resourceClass) {
87+
$maxDepth = $subresource->getMaxDepth();
88+
}
89+
90+
if (null !== $maxDepth && $depth >= $maxDepth) {
91+
break;
92+
}
8293
if (isset($visited[$visiting])) {
8394
continue;
8495
}
@@ -154,7 +165,7 @@ private function computeSubresourceOperations(string $resourceClass, array &$tre
154165

155166
$tree[$operation['route_name']] = $operation;
156167

157-
$this->computeSubresourceOperations($subresourceClass, $tree, $rootResourceClass, $operation, $visited + [$visiting => true]);
168+
$this->computeSubresourceOperations($subresourceClass, $tree, $rootResourceClass, $operation, $visited + [$visiting => true], ++$depth, $maxDepth);
158169
}
159170
}
160171
}

tests/Fixtures/FileConfigurations/resources.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
writableLink="false"
6464
required="true"
6565
>
66-
<subresource collection="true" resourceClass="Foo" />
66+
<subresource collection="true" resourceClass="Foo" maxDepth="1" />
6767
<attribute name="foo">
6868
<attribute>Foo</attribute>
6969
</attribute>

tests/Fixtures/FileConfigurations/resources.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ resources:
3232
iri: 'someirischema'
3333
properties:
3434
'foo':
35-
subresource: {collection: true, resourceClass: 'Foo'}
35+
subresource: {collection: true, resourceClass: 'Foo', maxDepth: 1}
3636
description: 'The dummy foo'
3737
readable: true
3838
writable: true

tests/Operation/Factory/SubresourceOperationFactoryTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,49 @@ public function testCreateByOverriding()
259259
] + SubresourceOperationFactory::ROUTE_OPTIONS,
260260
], $subresourceOperationFactory->create(DummyEntity::class));
261261
}
262+
263+
public function testCreateWithMaxDepth()
264+
{
265+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
266+
$resourceMetadataFactoryProphecy->create(RelatedDummyEntity::class)->shouldBeCalled()->willReturn(new ResourceMetadata('relatedDummyEntity'));
267+
$resourceMetadataFactoryProphecy->create(DummyEntity::class)->shouldBeCalled()->willReturn(new ResourceMetadata('dummyEntity'));
268+
269+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
270+
$propertyNameCollectionFactoryProphecy->create(DummyEntity::class)->shouldBeCalled()->willReturn(new PropertyNameCollection(['subresource']));
271+
$propertyNameCollectionFactoryProphecy->create(RelatedDummyEntity::class)->shouldBeCalled()->willReturn(new PropertyNameCollection(['bar', 'anotherSubresource']));
272+
273+
$subresourceMetadataCollectionWithMaxDepth = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(RelatedDummyEntity::class, false, 1));
274+
$anotherSubresourceMetadata = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(DummyEntity::class, false));
275+
276+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
277+
$propertyMetadataFactoryProphecy->create(DummyEntity::class, 'subresource')->shouldBeCalled()->willReturn($subresourceMetadataCollectionWithMaxDepth);
278+
$propertyMetadataFactoryProphecy->create(RelatedDummyEntity::class, 'bar')->shouldBeCalled()->willReturn(new PropertyMetadata());
279+
$propertyMetadataFactoryProphecy->create(RelatedDummyEntity::class, 'anotherSubresource')->shouldBeCalled()->willReturn($anotherSubresourceMetadata);
280+
281+
$pathSegmentNameGeneratorProphecy = $this->prophesize(PathSegmentNameGeneratorInterface::class);
282+
$pathSegmentNameGeneratorProphecy->getSegmentName('dummyEntity', true)->shouldBeCalled()->willReturn('dummy_entities');
283+
$pathSegmentNameGeneratorProphecy->getSegmentName('subresource', false)->shouldBeCalled()->willReturn('subresource');
284+
285+
$subresourceOperationFactory = new SubresourceOperationFactory(
286+
$resourceMetadataFactoryProphecy->reveal(),
287+
$propertyNameCollectionFactoryProphecy->reveal(),
288+
$propertyMetadataFactoryProphecy->reveal(),
289+
$pathSegmentNameGeneratorProphecy->reveal()
290+
);
291+
292+
$this->assertEquals([
293+
'api_dummy_entities_subresource_get_subresource' => [
294+
'property' => 'subresource',
295+
'collection' => false,
296+
'resource_class' => RelatedDummyEntity::class,
297+
'shortNames' => ['relatedDummyEntity', 'dummyEntity'],
298+
'identifiers' => [
299+
['id', DummyEntity::class, true],
300+
],
301+
'route_name' => 'api_dummy_entities_subresource_get_subresource',
302+
'path' => '/dummy_entities/{id}/subresource.{_format}',
303+
'operation_name' => 'subresource_get_subresource',
304+
] + SubresourceOperationFactory::ROUTE_OPTIONS,
305+
], $subresourceOperationFactory->create(DummyEntity::class));
306+
}
262307
}

0 commit comments

Comments
 (0)