Skip to content

Commit 9a14593

Browse files
committed
feat: allow to extend link handling
1 parent be7fbac commit 9a14593

13 files changed

+135
-24
lines changed
Lines changed: 45 additions & 0 deletions
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

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
use ApiPlatform\Metadata\Link;
2222
use ApiPlatform\Metadata\Operation;
2323
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
24-
use Psr\Container\ContainerInterface;
2524

2625
trait LinksHandlerTrait
2726
{
2827
private ?ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory;
29-
private ?ContainerInterface $handleLinksLocator;
3028

3129
/**
30+
* @param array{linkClass?: string, linkProperty?: string}&array<string, mixed> $context
31+
*
3232
* @return Link[]
3333
*/
3434
private function getLinks(string $resourceClass, Operation $operation, array $context): array
@@ -90,6 +90,9 @@ private function getLinks(string $resourceClass, Operation $operation, array $co
9090
return [$newLink];
9191
}
9292

93+
/**
94+
* @param array<int,mixed> $identifiers
95+
*/
9396
private function getIdentifierValue(array &$identifiers, string $name = null): mixed
9497
{
9598
if (isset($identifiers[$name])) {
@@ -102,6 +105,9 @@ private function getIdentifierValue(array &$identifiers, string $name = null): m
102105
return array_shift($identifiers);
103106
}
104107

108+
/**
109+
* @return ApiPlatform\Metadata\Link[]|array
110+
*/
105111
private function getOperationLinks(Operation $operation = null): array
106112
{
107113
if ($operation instanceof GraphQlOperation) {
@@ -114,22 +120,4 @@ private function getOperationLinks(Operation $operation = null): array
114120

115121
return [];
116122
}
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-
}
135123
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public function create(string $resourceClass): ResourceMetadataCollection
8282

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

src/Doctrine/Odm/State/CollectionProvider.php

Lines changed: 4 additions & 1 deletion
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

Lines changed: 4 additions & 1 deletion
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ private function addDefaults(Operation $operation): Operation
9191
$operation = $operation->withProvider($this->getProvider($operation));
9292
}
9393

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

src/Doctrine/Orm/State/CollectionProvider.php

Lines changed: 4 additions & 1 deletion
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

Lines changed: 4 additions & 1 deletion
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
Lines changed: 37 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
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,6 +28,8 @@ trait LinksHandlerTrait
2728
{
2829
use CommonLinksHandlerTrait;
2930

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

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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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)