Skip to content

Commit a749fe8

Browse files
authored
feat(doctrine): allow to extend link handling (#6061)
1 parent 312e3a1 commit a749fe8

13 files changed

+141
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\Doctrine\Common\State;
15+
16+
use ApiPlatform\Doctrine\Orm\State\Options;
17+
use ApiPlatform\Metadata\Exception\RuntimeException;
18+
use ApiPlatform\Metadata\Operation;
19+
use Psr\Container\ContainerInterface;
20+
21+
/**
22+
* @internal
23+
*/
24+
trait LinksHandlerLocatorTrait
25+
{
26+
private ?ContainerInterface $handleLinksLocator;
27+
28+
private function getLinksHandler(Operation $operation): ?callable
29+
{
30+
if (!($options = $operation->getStateOptions()) || !$options instanceof Options) {
31+
return null;
32+
}
33+
34+
$handleLinks = $options->getHandleLinks();
35+
if (\is_callable($handleLinks)) {
36+
return $handleLinks;
37+
}
38+
39+
if ($this->handleLinksLocator && \is_string($handleLinks) && $this->handleLinksLocator->has($handleLinks)) {
40+
return [$this->handleLinksLocator->get($handleLinks), 'handleLinks'];
41+
}
42+
43+
throw new RuntimeException(sprintf('Could not find handleLinks service "%s"', $handleLinks));
44+
}
45+
}

src/Doctrine/Common/State/LinksHandlerTrait.php

+10-23
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,17 @@
1818
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
1919
use ApiPlatform\Metadata\GraphQl\Query;
2020
use ApiPlatform\Metadata\HttpOperation;
21-
use ApiPlatform\Metadata\Link;
2221
use ApiPlatform\Metadata\Operation;
2322
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
24-
use Psr\Container\ContainerInterface;
2523

2624
trait LinksHandlerTrait
2725
{
2826
private ?ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory;
29-
private ?ContainerInterface $handleLinksLocator;
3027

3128
/**
32-
* @return Link[]
29+
* @param array{linkClass?: string, linkProperty?: string}&array<string, mixed> $context
30+
*
31+
* @return \ApiPlatform\Metadata\Link[]
3332
*/
3433
private function getLinks(string $resourceClass, Operation $operation, array $context): array
3534
{
@@ -90,9 +89,12 @@ private function getLinks(string $resourceClass, Operation $operation, array $co
9089
return [$newLink];
9190
}
9291

92+
/**
93+
* @param array<int|string,mixed> $identifiers
94+
*/
9395
private function getIdentifierValue(array &$identifiers, string $name = null): mixed
9496
{
95-
if (isset($identifiers[$name])) {
97+
if (null !== $name && isset($identifiers[$name])) {
9698
$value = $identifiers[$name];
9799
unset($identifiers[$name]);
98100

@@ -102,6 +104,9 @@ private function getIdentifierValue(array &$identifiers, string $name = null): m
102104
return array_shift($identifiers);
103105
}
104106

107+
/**
108+
* @return \ApiPlatform\Metadata\Link[]|array
109+
*/
105110
private function getOperationLinks(Operation $operation = null): array
106111
{
107112
if ($operation instanceof GraphQlOperation) {
@@ -114,22 +119,4 @@ private function getOperationLinks(Operation $operation = null): array
114119

115120
return [];
116121
}
117-
118-
private function getLinksHandler(Operation $operation): ?callable
119-
{
120-
if (!($options = $operation->getStateOptions()) || !method_exists($options, 'getHandleLinks') || null === $options->getHandleLinks()) {
121-
return null;
122-
}
123-
124-
$handleLinks = $options->getHandleLinks(); // @phpstan-ignore-line method_exists called above
125-
if (\is_callable($handleLinks)) {
126-
return $handleLinks;
127-
}
128-
129-
if ($this->handleLinksLocator && \is_string($handleLinks) && $this->handleLinksLocator->has($handleLinks)) {
130-
return [$this->handleLinksLocator->get($handleLinks), 'handleLinks'];
131-
}
132-
133-
throw new RuntimeException(sprintf('Could not find handleLinks service "%s"', $handleLinks));
134-
}
135122
}

src/Doctrine/Odm/Metadata/Resource/DoctrineMongoDbOdmResourceCollectionMetadataFactory.php

+6
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ public function create(string $resourceClass): ResourceMetadataCollection
8282

8383
private function addDefaults(Operation $operation): Operation
8484
{
85+
$options = $operation->getStateOptions() ?: new Options();
86+
if ($options instanceof Options && null === $options->getHandleLinks()) {
87+
$options = $options->withHandleLinks('api_platform.doctrine.odm.links_handler');
88+
$operation = $operation->withStateOptions($options);
89+
}
90+
8591
if (null === $operation->getProvider()) {
8692
$operation = $operation->withProvider($this->getProvider($operation));
8793
}

src/Doctrine/Odm/State/CollectionProvider.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Doctrine\Odm\State;
1515

16+
use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
1617
use ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface;
1718
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface;
1819
use ApiPlatform\Exception\RuntimeException;
@@ -29,15 +30,17 @@
2930
*/
3031
final class CollectionProvider implements ProviderInterface
3132
{
33+
use LinksHandlerLocatorTrait;
3234
use LinksHandlerTrait;
3335

3436
/**
3537
* @param AggregationCollectionExtensionInterface[] $collectionExtensions
3638
*/
37-
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
39+
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
3840
{
3941
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
4042
$this->handleLinksLocator = $handleLinksLocator;
43+
$this->managerRegistry = $managerRegistry;
4144
}
4245

4346
public function provide(Operation $operation, array $uriVariables = [], array $context = []): iterable

src/Doctrine/Odm/State/ItemProvider.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Doctrine\Odm\State;
1515

16+
use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
1617
use ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface;
1718
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultItemExtensionInterface;
1819
use ApiPlatform\Exception\RuntimeException;
@@ -32,15 +33,17 @@
3233
*/
3334
final class ItemProvider implements ProviderInterface
3435
{
36+
use LinksHandlerLocatorTrait;
3537
use LinksHandlerTrait;
3638

3739
/**
3840
* @param AggregationItemExtensionInterface[] $itemExtensions
3941
*/
40-
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
42+
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
4143
{
4244
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
4345
$this->handleLinksLocator = $handleLinksLocator;
46+
$this->managerRegistry = $managerRegistry;
4447
}
4548

4649
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object

src/Doctrine/Odm/State/LinksHandlerTrait.php

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Doctrine\ODM\MongoDB\Aggregation\Builder;
2121
use Doctrine\ODM\MongoDB\DocumentManager;
2222
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
23+
use Doctrine\Persistence\ManagerRegistry;
2324

2425
/**
2526
* @internal
@@ -28,6 +29,8 @@ trait LinksHandlerTrait
2829
{
2930
use CommonLinksHandlerTrait;
3031

32+
private ManagerRegistry $managerRegistry;
33+
3134
private function handleLinks(Builder $aggregationBuilder, array $identifiers, array $context, string $resourceClass, Operation $operation = null): void
3235
{
3336
if (!$identifiers) {

src/Doctrine/Orm/Metadata/Resource/DoctrineOrmResourceCollectionMetadataFactory.php

+6
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ private function addDefaults(Operation $operation): Operation
9191
$operation = $operation->withProvider($this->getProvider($operation));
9292
}
9393

94+
$options = $operation->getStateOptions() ?: new Options();
95+
if ($options instanceof Options && null === $options->getHandleLinks()) {
96+
$options = $options->withHandleLinks('api_platform.doctrine.orm.links_handler');
97+
$operation = $operation->withStateOptions($options);
98+
}
99+
94100
if (null === $operation->getProcessor()) {
95101
$operation = $operation->withProcessor($this->getProcessor($operation));
96102
}

src/Doctrine/Orm/State/CollectionProvider.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Doctrine\Orm\State;
1515

16+
use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
1617
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
1718
use ApiPlatform\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
1819
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
@@ -32,15 +33,17 @@
3233
*/
3334
final class CollectionProvider implements ProviderInterface
3435
{
36+
use LinksHandlerLocatorTrait;
3537
use LinksHandlerTrait;
3638

3739
/**
3840
* @param QueryCollectionExtensionInterface[] $collectionExtensions
3941
*/
40-
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
42+
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
4143
{
4244
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
4345
$this->handleLinksLocator = $handleLinksLocator;
46+
$this->managerRegistry = $managerRegistry;
4447
}
4548

4649
public function provide(Operation $operation, array $uriVariables = [], array $context = []): iterable

src/Doctrine/Orm/State/ItemProvider.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Doctrine\Orm\State;
1515

16+
use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
1617
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
1718
use ApiPlatform\Doctrine\Orm\Extension\QueryResultItemExtensionInterface;
1819
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
@@ -32,15 +33,17 @@
3233
*/
3334
final class ItemProvider implements ProviderInterface
3435
{
36+
use LinksHandlerLocatorTrait;
3537
use LinksHandlerTrait;
3638

3739
/**
3840
* @param QueryItemExtensionInterface[] $itemExtensions
3941
*/
40-
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
42+
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
4143
{
4244
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
4345
$this->handleLinksLocator = $handleLinksLocator;
46+
$this->managerRegistry = $managerRegistry;
4447
}
4548

4649
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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\Doctrine\Orm\State;
15+
16+
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
17+
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
18+
use Doctrine\ORM\QueryBuilder;
19+
use Doctrine\Persistence\ManagerRegistry;
20+
21+
final class LinksHandler implements LinksHandlerInterface
22+
{
23+
use LinksHandlerTrait {
24+
handleLinks as private handle;
25+
}
26+
27+
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry)
28+
{
29+
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
30+
$this->managerRegistry = $managerRegistry;
31+
}
32+
33+
public function handleLinks(QueryBuilder $queryBuilder, array $uriVariables, QueryNameGeneratorInterface $queryNameGenerator, array $context): void
34+
{
35+
$this->handle($queryBuilder, $uriVariables, $queryNameGenerator, $context, $context['entityClass'], $context['operation']);
36+
}
37+
}

src/Doctrine/Orm/State/LinksHandlerTrait.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
namespace ApiPlatform\Doctrine\Orm\State;
1515

1616
use ApiPlatform\Doctrine\Common\State\LinksHandlerTrait as CommonLinksHandlerTrait;
17-
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
17+
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
1818
use ApiPlatform\Metadata\Link;
1919
use ApiPlatform\Metadata\Operation;
2020
use Doctrine\ORM\Mapping\ClassMetadataInfo;
2121
use Doctrine\ORM\QueryBuilder;
22+
use Doctrine\Persistence\ManagerRegistry;
2223

2324
/**
2425
* @internal
@@ -27,7 +28,9 @@ trait LinksHandlerTrait
2728
{
2829
use CommonLinksHandlerTrait;
2930

30-
private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, QueryNameGenerator $queryNameGenerator, array $context, string $entityClass, Operation $operation): void
31+
private ManagerRegistry $managerRegistry;
32+
33+
private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, QueryNameGeneratorInterface $queryNameGenerator, array $context, string $entityClass, Operation $operation): void
3134
{
3235
if (!$identifiers) {
3336
return;

src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.xml

+7
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@
151151
<argument type="service" id="doctrine_mongodb" />
152152
<argument type="service" id="api_platform.doctrine.odm.metadata.resource.metadata_collection_factory.inner" />
153153
</service>
154+
155+
<service id="api_platform.doctrine.odm.links_handler" class="ApiPlatform\Doctrine\Odm\State\LinksHandler">
156+
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
157+
<argument type="service" id="doctrine_mongodb" />
158+
159+
<tag name="api_platform.doctrine.odm.links_handler" key="api_platform.doctrine.odm.links_handler" />
160+
</service>
154161
</services>
155162

156163
</container>

src/Symfony/Bundle/Resources/config/doctrine_orm.xml

+6
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@
171171
<argument type="service" id="api_platform.doctrine.orm.metadata.resource.link_factory.inner" />
172172
</service>
173173

174+
<service id="api_platform.doctrine.orm.links_handler" class="ApiPlatform\Doctrine\Orm\State\LinksHandler">
175+
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
176+
<argument type="service" id="doctrine" />
177+
178+
<tag name="api_platform.doctrine.orm.links_handler" key="api_platform.doctrine.orm.links_handler" />
179+
</service>
174180
</services>
175181

176182
</container>

0 commit comments

Comments
 (0)