Skip to content

Commit 0eb9602

Browse files
authored
Merge pull request #2021 from MoltenCoreIO/fix-subresource_depth
Fix issue #1711 - Subresource Depth bug
2 parents 9515552 + 668deb1 commit 0eb9602

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

src/Operation/Factory/SubresourceOperationFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ private function computeSubresourceOperations(string $resourceClass, array &$tre
100100
continue;
101101
}
102102

103+
if ($rootResourceClass === $resourceClass) {
104+
// reset depth when we return to rootResourceClass
105+
$depth = 0;
106+
}
107+
103108
$rootResourceMetadata = $this->resourceMetadataFactory->create($rootResourceClass);
104109
$operationName = 'get';
105110
$operation = [

tests/Operation/Factory/SubresourceOperationFactoryTest.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use ApiPlatform\Core\Operation\Factory\SubresourceOperationFactory;
2424
use ApiPlatform\Core\Operation\PathSegmentNameGeneratorInterface;
2525
use ApiPlatform\Core\Tests\Fixtures\DummyEntity;
26+
use ApiPlatform\Core\Tests\Fixtures\DummyValidatedEntity;
2627
use ApiPlatform\Core\Tests\Fixtures\RelatedDummyEntity;
2728
use PHPUnit\Framework\TestCase;
2829

@@ -305,6 +306,91 @@ public function testCreateWithMaxDepth()
305306
], $subresourceOperationFactory->create(DummyEntity::class));
306307
}
307308

309+
/**
310+
* Test for issue: https://github.com/api-platform/core/issues/1711.
311+
*/
312+
public function testCreateWithMaxDepthMultipleSubresources()
313+
{
314+
/**
315+
* DummyEntity -subresource-> RelatedDummyEntity -anotherSubresource-> DummyEntity
316+
* DummyEntity -secondSubresource-> dummyValidatedEntity -moreSubresource-> RelatedDummyEntity.
317+
*/
318+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
319+
$resourceMetadataFactoryProphecy->create(RelatedDummyEntity::class)->shouldBeCalled()->willReturn(new ResourceMetadata('relatedDummyEntity'));
320+
$resourceMetadataFactoryProphecy->create(DummyEntity::class)->shouldBeCalled()->willReturn(new ResourceMetadata('dummyEntity'));
321+
$resourceMetadataFactoryProphecy->create(DummyValidatedEntity::class)->shouldBeCalled()->willReturn(new ResourceMetadata('dummyValidatedEntity'));
322+
323+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
324+
$propertyNameCollectionFactoryProphecy->create(DummyEntity::class)->shouldBeCalled()->willReturn(new PropertyNameCollection(['subresource', 'secondSubresource']));
325+
$propertyNameCollectionFactoryProphecy->create(RelatedDummyEntity::class)->shouldBeCalled()->willReturn(new PropertyNameCollection(['bar', 'anotherSubresource']));
326+
$propertyNameCollectionFactoryProphecy->create(DummyValidatedEntity::class)->shouldBeCalled()->willReturn(new PropertyNameCollection(['moreSubresource']));
327+
328+
$subresourceMetadataCollectionWithMaxDepth = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(RelatedDummyEntity::class, false, 1));
329+
$anotherSubresourceMetadata = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(DummyEntity::class, false));
330+
$secondSubresourceMetadata = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(DummyValidatedEntity::class, false, 2));
331+
$moreSubresourceMetadata = (new PropertyMetadata())->withSubresource(new SubresourceMetadata(RelatedDummyEntity::class, false));
332+
333+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
334+
$propertyMetadataFactoryProphecy->create(DummyEntity::class, 'subresource')->shouldBeCalled()->willReturn($subresourceMetadataCollectionWithMaxDepth);
335+
$propertyMetadataFactoryProphecy->create(DummyEntity::class, 'secondSubresource')->shouldBeCalled()->willReturn($secondSubresourceMetadata);
336+
$propertyMetadataFactoryProphecy->create(RelatedDummyEntity::class, 'bar')->shouldBeCalled()->willReturn(new PropertyMetadata());
337+
$propertyMetadataFactoryProphecy->create(RelatedDummyEntity::class, 'anotherSubresource')->shouldBeCalled()->willReturn($anotherSubresourceMetadata);
338+
$propertyMetadataFactoryProphecy->create(DummyValidatedEntity::class, 'moreSubresource')->shouldBeCalled()->willReturn($moreSubresourceMetadata);
339+
340+
$pathSegmentNameGeneratorProphecy = $this->prophesize(PathSegmentNameGeneratorInterface::class);
341+
$pathSegmentNameGeneratorProphecy->getSegmentName('dummyEntity', true)->shouldBeCalled()->willReturn('dummy_entities');
342+
$pathSegmentNameGeneratorProphecy->getSegmentName('subresource', false)->shouldBeCalled()->willReturn('subresources');
343+
$pathSegmentNameGeneratorProphecy->getSegmentName('secondSubresource', false)->shouldBeCalled()->willReturn('second_subresources');
344+
$pathSegmentNameGeneratorProphecy->getSegmentName('moreSubresource', false)->shouldBeCalled()->willReturn('mode_subresources');
345+
346+
$subresourceOperationFactory = new SubresourceOperationFactory(
347+
$resourceMetadataFactoryProphecy->reveal(),
348+
$propertyNameCollectionFactoryProphecy->reveal(),
349+
$propertyMetadataFactoryProphecy->reveal(),
350+
$pathSegmentNameGeneratorProphecy->reveal()
351+
);
352+
353+
$this->assertEquals([
354+
'api_dummy_entities_subresource_get_subresource' => [
355+
'property' => 'subresource',
356+
'collection' => false,
357+
'resource_class' => RelatedDummyEntity::class,
358+
'shortNames' => ['relatedDummyEntity', 'dummyEntity'],
359+
'identifiers' => [
360+
['id', DummyEntity::class, true],
361+
],
362+
'route_name' => 'api_dummy_entities_subresource_get_subresource',
363+
'path' => '/dummy_entities/{id}/subresources.{_format}',
364+
'operation_name' => 'subresource_get_subresource',
365+
] + SubresourceOperationFactory::ROUTE_OPTIONS,
366+
'api_dummy_entities_second_subresource_get_subresource' => [
367+
'property' => 'secondSubresource',
368+
'collection' => false,
369+
'resource_class' => DummyValidatedEntity::class,
370+
'shortNames' => ['dummyValidatedEntity', 'dummyEntity'],
371+
'identifiers' => [
372+
['id', DummyEntity::class, true],
373+
],
374+
'route_name' => 'api_dummy_entities_second_subresource_get_subresource',
375+
'path' => '/dummy_entities/{id}/second_subresources.{_format}',
376+
'operation_name' => 'second_subresource_get_subresource',
377+
] + SubresourceOperationFactory::ROUTE_OPTIONS,
378+
'api_dummy_entities_second_subresource_more_subresource_get_subresource' => [
379+
'property' => 'moreSubresource',
380+
'collection' => false,
381+
'resource_class' => RelatedDummyEntity::class,
382+
'shortNames' => ['relatedDummyEntity', 'dummyValidatedEntity'],
383+
'identifiers' => [
384+
['id', DummyEntity::class, true],
385+
['secondSubresource', DummyValidatedEntity::class, false],
386+
],
387+
'route_name' => 'api_dummy_entities_second_subresource_more_subresource_get_subresource',
388+
'path' => '/dummy_entities/{id}/second_subresources/mode_subresources.{_format}',
389+
'operation_name' => 'second_subresource_more_subresource_get_subresource',
390+
] + SubresourceOperationFactory::ROUTE_OPTIONS,
391+
], $subresourceOperationFactory->create(DummyEntity::class));
392+
}
393+
308394
public function testCreateWithEnd()
309395
{
310396
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);

0 commit comments

Comments
 (0)