Skip to content

Commit 13751eb

Browse files
authored
Merge pull request #1996 from oxan/fix-fatal-error
Fix fatal error when subresource type is not defined
2 parents 0eb9602 + 471f86e commit 13751eb

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

src/Metadata/Property/Factory/AnnotationSubresourceMetadataFactory.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Core\Metadata\Property\Factory;
1515

1616
use ApiPlatform\Core\Annotation\ApiSubresource;
17+
use ApiPlatform\Core\Exception\InvalidResourceException;
1718
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
1819
use ApiPlatform\Core\Metadata\Property\SubresourceMetadata;
1920
use ApiPlatform\Core\Util\Reflection;
@@ -52,7 +53,7 @@ public function create(string $resourceClass, string $property, array $options =
5253
$annotation = $this->reader->getPropertyAnnotation($reflectionClass->getProperty($property), ApiSubresource::class);
5354

5455
if (null !== $annotation) {
55-
return $this->updateMetadata($annotation, $propertyMetadata, $resourceClass);
56+
return $this->updateMetadata($annotation, $propertyMetadata, $resourceClass, $property);
5657
}
5758
}
5859

@@ -70,16 +71,19 @@ public function create(string $resourceClass, string $property, array $options =
7071
$annotation = $this->reader->getMethodAnnotation($reflectionMethod, ApiSubresource::class);
7172

7273
if (null !== $annotation) {
73-
return $this->updateMetadata($annotation, $propertyMetadata, $resourceClass);
74+
return $this->updateMetadata($annotation, $propertyMetadata, $resourceClass, $property);
7475
}
7576
}
7677

7778
return $propertyMetadata;
7879
}
7980

80-
private function updateMetadata(ApiSubresource $annotation, PropertyMetadata $propertyMetadata, string $originResourceClass): PropertyMetadata
81+
private function updateMetadata(ApiSubresource $annotation, PropertyMetadata $propertyMetadata, string $originResourceClass, string $propertyName): PropertyMetadata
8182
{
8283
$type = $propertyMetadata->getType();
84+
if (null === $type) {
85+
throw new InvalidResourceException(sprintf('Property "%s" on resource "%s" is declared as a subresource, but its type could not be determined.', $propertyName, $originResourceClass));
86+
}
8387
$isCollection = $type->isCollection();
8488
$resourceClass = $isCollection ? $type->getCollectionValueType()->getClassName() : $type->getClassName();
8589
$maxDepth = $annotation->maxDepth;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Metadata\Property\Factory;
15+
16+
use ApiPlatform\Core\Annotation\ApiSubresource;
17+
use ApiPlatform\Core\Metadata\Property\Factory\AnnotationSubresourceMetadataFactory;
18+
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
19+
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
20+
use ApiPlatform\Core\Metadata\Property\SubresourceMetadata;
21+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
22+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
23+
use Doctrine\Common\Annotations\Reader;
24+
use Doctrine\Common\Collections\ArrayCollection;
25+
use PHPUnit\Framework\TestCase;
26+
use Prophecy\Argument;
27+
use Prophecy\Prophecy\ProphecyInterface;
28+
use Symfony\Component\PropertyInfo\Type;
29+
30+
class AnnotationSubresourceMetadataFactoryTest extends TestCase
31+
{
32+
/**
33+
* @dataProvider getDependencies
34+
*/
35+
public function testCreateProperty(ProphecyInterface $reader, ProphecyInterface $decorated = null)
36+
{
37+
$factory = new AnnotationSubresourceMetadataFactory($reader->reveal(), $decorated->reveal());
38+
$metadata = $factory->create(Dummy::class, 'relatedDummies');
39+
40+
$this->assertEquals(new SubresourceMetadata(RelatedDummy::class, true, null), $metadata->getSubresource());
41+
}
42+
43+
public function getDependencies()
44+
{
45+
$annotation = new ApiSubresource();
46+
47+
$propertyReaderProphecy = $this->prophesize(Reader::class);
48+
$propertyReaderProphecy->getPropertyAnnotation(Argument::type(\ReflectionProperty::class), ApiSubresource::class)->willReturn($annotation)->shouldBeCalled();
49+
50+
$relatedDummyType = new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class);
51+
$subresourceType = new Type(Type::BUILTIN_TYPE_OBJECT, false, ArrayCollection::class, true, new Type(Type::BUILTIN_TYPE_INT), $relatedDummyType);
52+
53+
$decoratedReturnProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
54+
$decoratedReturnProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn(new PropertyMetadata($subresourceType, 'Several dummies'))->shouldBeCalled();
55+
56+
return [
57+
[$propertyReaderProphecy, $decoratedReturnProphecy],
58+
];
59+
}
60+
61+
/**
62+
* @expectedException \ApiPlatform\Core\Exception\InvalidResourceException
63+
* @expectedExceptionMessage Property "relatedDummies" on resource "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" is declared as a subresource, but its type could not be determined.
64+
*/
65+
public function testCreatePropertyUnknownType()
66+
{
67+
$annotation = new ApiSubresource();
68+
69+
$propertyReaderProphecy = $this->prophesize(Reader::class);
70+
$propertyReaderProphecy->getPropertyAnnotation(Argument::type(\ReflectionProperty::class), ApiSubresource::class)->willReturn($annotation)->shouldBeCalled();
71+
72+
$decoratedReturnProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
73+
$decoratedReturnProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn(new PropertyMetadata(null, 'Several dummies'))->shouldBeCalled();
74+
75+
$factory = new AnnotationSubresourceMetadataFactory($propertyReaderProphecy->reveal(), $decoratedReturnProphecy->reveal());
76+
$metadata = $factory->create(Dummy::class, 'relatedDummies');
77+
}
78+
}

0 commit comments

Comments
 (0)