Skip to content

Commit ad14ac0

Browse files
greg0iremeyerbaptiste
authored andcommitted
Generator compat improvements (#1429)
1 parent 62ffeae commit ad14ac0

10 files changed

+167
-31
lines changed

src/Bridge/Doctrine/Orm/CollectionDataProvider.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
1818
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
1919
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
20-
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
20+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
2121
use ApiPlatform\Core\Exception\RuntimeException;
2222
use Doctrine\Common\Persistence\ManagerRegistry;
2323

@@ -27,7 +27,7 @@
2727
* @author Kévin Dunglas <dunglas@gmail.com>
2828
* @author Samuel ROZE <samuel.roze@gmail.com>
2929
*/
30-
class CollectionDataProvider implements CollectionDataProviderInterface
30+
class CollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
3131
{
3232
private $managerRegistry;
3333
private $collectionExtensions;
@@ -42,6 +42,11 @@ public function __construct(ManagerRegistry $managerRegistry, array $collectionE
4242
$this->collectionExtensions = $collectionExtensions;
4343
}
4444

45+
public function supports(string $resourceClass, string $operationName = null): bool
46+
{
47+
return null !== $this->managerRegistry->getManagerForClass($resourceClass);
48+
}
49+
4550
/**
4651
* {@inheritdoc}
4752
*
@@ -50,9 +55,6 @@ public function __construct(ManagerRegistry $managerRegistry, array $collectionE
5055
public function getCollection(string $resourceClass, string $operationName = null)
5156
{
5257
$manager = $this->managerRegistry->getManagerForClass($resourceClass);
53-
if (null === $manager) {
54-
throw new ResourceClassNotSupportedException();
55-
}
5658

5759
$repository = $manager->getRepository($resourceClass);
5860
if (!method_exists($repository, 'createQueryBuilder')) {

src/Bridge/Doctrine/Orm/ItemDataProvider.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\IdentifierManagerTrait;
1919
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
2020
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
21-
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
21+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
2222
use ApiPlatform\Core\Exception\RuntimeException;
2323
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2424
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
@@ -32,7 +32,7 @@
3232
* @author Kévin Dunglas <dunglas@gmail.com>
3333
* @author Samuel ROZE <samuel.roze@gmail.com>
3434
*/
35-
class ItemDataProvider implements ItemDataProviderInterface
35+
class ItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
3636
{
3737
use IdentifierManagerTrait;
3838

@@ -53,6 +53,11 @@ public function __construct(ManagerRegistry $managerRegistry, PropertyNameCollec
5353
$this->itemExtensions = $itemExtensions;
5454
}
5555

56+
public function supports(string $resourceClass, string $operationName = null): bool
57+
{
58+
return null !== $this->managerRegistry->getManagerForClass($resourceClass);
59+
}
60+
5661
/**
5762
* {@inheritdoc}
5863
*
@@ -63,9 +68,6 @@ public function __construct(ManagerRegistry $managerRegistry, PropertyNameCollec
6368
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
6469
{
6570
$manager = $this->managerRegistry->getManagerForClass($resourceClass);
66-
if (null === $manager) {
67-
throw new ResourceClassNotSupportedException();
68-
}
6971

7072
$identifiers = $this->normalizeIdentifiers($id, $manager, $resourceClass);
7173

src/DataProvider/ChainCollectionDataProvider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,14 @@ public function getCollection(string $resourceClass, string $operationName = nul
3939
{
4040
foreach ($this->dataProviders as $dataProvider) {
4141
try {
42+
if ($dataProvider instanceof RestrictedDataProviderInterface
43+
&& !$dataProvider->supports($resourceClass, $operationName)) {
44+
continue;
45+
}
46+
4247
return $dataProvider->getCollection($resourceClass, $operationName);
4348
} catch (ResourceClassNotSupportedException $e) {
49+
@trigger_error(sprintf('Throwing a "%s" in a data provider is deprecated in favor of implementing "%s"', ResourceClassNotSupportedException::class, RestrictedDataProviderInterface::class), E_USER_DEPRECATED);
4450
continue;
4551
}
4652
}

src/DataProvider/ChainItemDataProvider.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,16 @@ public function __construct(array $dataProviders)
3737
*/
3838
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
3939
{
40-
foreach ($this->dataProviders as $dataProviders) {
40+
foreach ($this->dataProviders as $dataProvider) {
4141
try {
42-
return $dataProviders->getItem($resourceClass, $id, $operationName, $context);
42+
if ($dataProvider instanceof RestrictedDataProviderInterface
43+
&& !$dataProvider->supports($resourceClass, $operationName)) {
44+
continue;
45+
}
46+
47+
return $dataProvider->getItem($resourceClass, $id, $operationName, $context);
4348
} catch (ResourceClassNotSupportedException $e) {
49+
@trigger_error(sprintf('Throwing a "%s" is deprecated in favor of implementing "%s"', get_class($e), RestrictedDataProviderInterface::class), E_USER_DEPRECATED);
4450
continue;
4551
}
4652
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
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\DataProvider;
15+
16+
/**
17+
* Restricts a data provider based on a condition.
18+
*/
19+
interface RestrictedDataProviderInterface
20+
{
21+
public function supports(string $resourceClass, string $operationName = null): bool;
22+
}

tests/Bridge/Doctrine/Orm/CollectionDataProviderTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,14 @@ public function testCannotCreateQueryBuilder()
9898
$this->assertEquals([], $dataProvider->getCollection(Dummy::class, 'foo'));
9999
}
100100

101-
/**
102-
* @expectedException \ApiPlatform\Core\Exception\ResourceClassNotSupportedException
103-
*/
104-
public function testThrowResourceClassNotSupportedException()
101+
public function testUnsupportedClass()
105102
{
106103
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
107104
$managerRegistryProphecy->getManagerForClass(Dummy::class)->willReturn(null)->shouldBeCalled();
108105

109106
$extensionProphecy = $this->prophesize(QueryResultCollectionExtensionInterface::class);
110107

111108
$dataProvider = new CollectionDataProvider($managerRegistryProphecy->reveal(), [$extensionProphecy->reveal()]);
112-
$dataProvider->getCollection(Dummy::class, 'foo');
109+
$this->assertFalse($dataProvider->supports(Dummy::class, 'foo'));
113110
}
114111
}

tests/Bridge/Doctrine/Orm/ItemDataProviderTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,7 @@ public function testQueryResultExtension()
178178
$this->assertEquals([], $dataProvider->getItem(Dummy::class, 1, 'foo'));
179179
}
180180

181-
/**
182-
* @expectedException \ApiPlatform\Core\Exception\ResourceClassNotSupportedException
183-
*/
184-
public function testThrowResourceClassNotSupportedException()
181+
public function testUnsupportedClass()
185182
{
186183
$managerRegistryProphecy = $this->prophesize(ManagerRegistry::class);
187184
$managerRegistryProphecy->getManagerForClass(Dummy::class)->willReturn(null)->shouldBeCalled();
@@ -193,7 +190,7 @@ public function testThrowResourceClassNotSupportedException()
193190
]);
194191

195192
$dataProvider = new ItemDataProvider($managerRegistryProphecy->reveal(), $propertyNameCollectionFactory, $propertyMetadataFactory, [$extensionProphecy->reveal()]);
196-
$dataProvider->getItem(Dummy::class, 'foo');
193+
$this->assertFalse($dataProvider->supports(Dummy::class, 'foo'));
197194
}
198195

199196
/**

tests/DataProvider/ChainCollectionDataProviderTest.php

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\DataProvider\ChainCollectionDataProvider;
1717
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
18+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
1819
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
2021
use PHPUnit\Framework\TestCase;
@@ -34,7 +35,57 @@ public function testGetCollection()
3435
$dummy2->setName('Parks');
3536

3637
$firstDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
37-
$firstDataProvider->getCollection(Dummy::class, null)->willReturn([$dummy, $dummy2])->willThrow(ResourceClassNotSupportedException::class);
38+
$firstDataProvider->willImplement(RestrictedDataProviderInterface::class);
39+
$firstDataProvider->supports(Dummy::class, null)->willReturn(false);
40+
41+
$secondDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
42+
$secondDataProvider->willImplement(RestrictedDataProviderInterface::class);
43+
$secondDataProvider->supports(Dummy::class, null)->willReturn(true);
44+
$secondDataProvider->getCollection(Dummy::class, null)
45+
->willReturn([$dummy, $dummy2]);
46+
47+
$thirdDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
48+
$thirdDataProvider->willImplement(RestrictedDataProviderInterface::class);
49+
$thirdDataProvider->supports(Dummy::class, null)->willReturn(true);
50+
$thirdDataProvider->getCollection(Dummy::class, null)->willReturn([$dummy]);
51+
52+
$chainItemDataProvider = new ChainCollectionDataProvider([
53+
$firstDataProvider->reveal(),
54+
$secondDataProvider->reveal(),
55+
$thirdDataProvider->reveal(),
56+
]);
57+
58+
$this->assertEquals(
59+
[$dummy, $dummy2],
60+
$chainItemDataProvider->getCollection(Dummy::class)
61+
);
62+
}
63+
64+
public function testGetCollectionNotSupported()
65+
{
66+
$firstDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
67+
$firstDataProvider->willImplement(RestrictedDataProviderInterface::class);
68+
$firstDataProvider->supports('notfound', 'op')->willReturn(false);
69+
70+
$collection = (new ChainCollectionDataProvider([$firstDataProvider->reveal()]))->getCollection('notfound', 'op');
71+
72+
$this->assertTrue(is_array($collection) || $collection instanceof \Traversable);
73+
$this->assertEmpty($collection);
74+
}
75+
76+
/**
77+
* @group legacy
78+
* @expectedDeprecation Throwing a "ApiPlatform\Core\Exception\ResourceClassNotSupportedException" in a data provider is deprecated in favor of implementing "ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface"
79+
*/
80+
public function testLegacyGetCollection()
81+
{
82+
$dummy = new Dummy();
83+
$dummy->setName('Rosa');
84+
$dummy2 = new Dummy();
85+
$dummy2->setName('Parks');
86+
87+
$firstDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
88+
$firstDataProvider->getCollection(Dummy::class, null)->willThrow(ResourceClassNotSupportedException::class);
3889

3990
$secondDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
4091
$secondDataProvider->getCollection(Dummy::class, null)->willReturn([$dummy, $dummy2]);
@@ -47,7 +98,11 @@ public function testGetCollection()
4798
$this->assertEquals([$dummy, $dummy2], $chainItemDataProvider->getCollection(Dummy::class));
4899
}
49100

50-
public function testGetCollectionExceptions()
101+
/**
102+
* @group legacy
103+
* @expectedDeprecation Throwing a "ApiPlatform\Core\Exception\ResourceClassNotSupportedException" in a data provider is deprecated in favor of implementing "ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface"
104+
*/
105+
public function testLegacyGetCollectionExceptions()
51106
{
52107
$firstDataProvider = $this->prophesize(CollectionDataProviderInterface::class);
53108
$firstDataProvider->getCollection('notfound', 'op')->willThrow(ResourceClassNotSupportedException::class);

tests/DataProvider/ChainItemDataProviderTest.php

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\DataProvider\ChainItemDataProvider;
1717
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
18+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
1819
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
1920
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
2021
use PHPUnit\Framework\TestCase;
@@ -31,6 +32,49 @@ public function testGetItem()
3132
$dummy = new Dummy();
3233
$dummy->setName('Lucie');
3334

35+
$firstDataProvider = $this->prophesize(ItemDataProviderInterface::class);
36+
$firstDataProvider->willImplement(RestrictedDataProviderInterface::class);
37+
$firstDataProvider->supports(Dummy::class, null)->willReturn(false);
38+
39+
$secondDataProvider = $this->prophesize(ItemDataProviderInterface::class);
40+
$secondDataProvider->willImplement(RestrictedDataProviderInterface::class);
41+
$secondDataProvider->supports(Dummy::class, null)->willReturn(true);
42+
$secondDataProvider->getItem(Dummy::class, 1, null, [])->willReturn($dummy);
43+
44+
$thirdDataProvider = $this->prophesize(ItemDataProviderInterface::class);
45+
$thirdDataProvider->willImplement(RestrictedDataProviderInterface::class);
46+
$thirdDataProvider->supports(Dummy::class, null)->willReturn(true);
47+
$thirdDataProvider->getItem(Dummy::class, 1, null, [])->willReturn(new \stdClass());
48+
49+
$chainItemDataProvider = new ChainItemDataProvider([
50+
$firstDataProvider->reveal(),
51+
$secondDataProvider->reveal(),
52+
$thirdDataProvider->reveal(),
53+
]);
54+
55+
$this->assertEquals($dummy, $chainItemDataProvider->getItem(Dummy::class, 1));
56+
}
57+
58+
public function testGetItemExceptions()
59+
{
60+
$firstDataProvider = $this->prophesize(ItemDataProviderInterface::class);
61+
$firstDataProvider->willImplement(RestrictedDataProviderInterface::class);
62+
$firstDataProvider->supports('notfound', null)->willReturn(false);
63+
64+
$chainItemDataProvider = new ChainItemDataProvider([$firstDataProvider->reveal()]);
65+
66+
$this->assertEquals('', $chainItemDataProvider->getItem('notfound', 1));
67+
}
68+
69+
/**
70+
* @group legacy
71+
* @expectedDeprecation Throwing a "ApiPlatform\Core\Exception\ResourceClassNotSupportedException" is deprecated in favor of implementing "ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface"
72+
*/
73+
public function testLegacyGetItem()
74+
{
75+
$dummy = new Dummy();
76+
$dummy->setName('Lucie');
77+
3478
$firstDataProvider = $this->prophesize(ItemDataProviderInterface::class);
3579
$firstDataProvider->getItem(Dummy::class, 1, null, [])->willThrow(ResourceClassNotSupportedException::class);
3680

@@ -45,7 +89,11 @@ public function testGetItem()
4589
$this->assertEquals($dummy, $chainItemDataProvider->getItem(Dummy::class, 1));
4690
}
4791

48-
public function testGetItemExeptions()
92+
/**
93+
* @group legacy
94+
* @expectedDeprecation Throwing a "ApiPlatform\Core\Exception\ResourceClassNotSupportedException" is deprecated in favor of implementing "ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface"
95+
*/
96+
public function testLegacyGetItemExceptions()
4997
{
5098
$firstDataProvider = $this->prophesize(ItemDataProviderInterface::class);
5199
$firstDataProvider->getItem('notfound', 1, null, [])->willThrow(ResourceClassNotSupportedException::class);

tests/Fixtures/TestBundle/DataProvider/ContainNonResourceItemDataProvider.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,25 @@
1414
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\DataProvider;
1515

1616
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
17-
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
17+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
1818
use ApiPlatform\Core\Tests\Fixtures\NotAResource;
1919
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\ContainNonResource;
2020

2121
/**
2222
* @author Kévin Dunglas <dunglas@gmail.com>
2323
*/
24-
class ContainNonResourceItemDataProvider implements ItemDataProviderInterface
24+
class ContainNonResourceItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
2525
{
26+
public function supports(string $resourceClass, string $operationName = null): bool
27+
{
28+
return ContainNonResource::class === $resourceClass;
29+
}
30+
2631
/**
2732
* {@inheritdoc}
2833
*/
2934
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
3035
{
31-
if (ContainNonResource::class !== $resourceClass) {
32-
throw new ResourceClassNotSupportedException();
33-
}
34-
3536
// Retrieve the blog post item from somewhere
3637
$cnr = new ContainNonResource();
3738
$cnr->id = $id;

0 commit comments

Comments
 (0)