Skip to content

Commit

Permalink
feat(doctrine): allow to extend link handling (#6061)
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka authored Dec 29, 2023
1 parent 312e3a1 commit a749fe8
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 29 deletions.
45 changes: 45 additions & 0 deletions src/Doctrine/Common/State/LinksHandlerLocatorTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Doctrine\Common\State;

use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\Exception\RuntimeException;
use ApiPlatform\Metadata\Operation;
use Psr\Container\ContainerInterface;

/**
* @internal
*/
trait LinksHandlerLocatorTrait
{
private ?ContainerInterface $handleLinksLocator;

private function getLinksHandler(Operation $operation): ?callable
{
if (!($options = $operation->getStateOptions()) || !$options instanceof Options) {
return null;
}

$handleLinks = $options->getHandleLinks();
if (\is_callable($handleLinks)) {
return $handleLinks;
}

if ($this->handleLinksLocator && \is_string($handleLinks) && $this->handleLinksLocator->has($handleLinks)) {
return [$this->handleLinksLocator->get($handleLinks), 'handleLinks'];
}

throw new RuntimeException(sprintf('Could not find handleLinks service "%s"', $handleLinks));
}
}
33 changes: 10 additions & 23 deletions src/Doctrine/Common/State/LinksHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,17 @@
use ApiPlatform\Metadata\GraphQl\Operation as GraphQlOperation;
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\HttpOperation;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use Psr\Container\ContainerInterface;

trait LinksHandlerTrait
{
private ?ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory;
private ?ContainerInterface $handleLinksLocator;

/**
* @return Link[]
* @param array{linkClass?: string, linkProperty?: string}&array<string, mixed> $context
*
* @return \ApiPlatform\Metadata\Link[]
*/
private function getLinks(string $resourceClass, Operation $operation, array $context): array
{
Expand Down Expand Up @@ -90,9 +89,12 @@ private function getLinks(string $resourceClass, Operation $operation, array $co
return [$newLink];
}

/**
* @param array<int|string,mixed> $identifiers
*/
private function getIdentifierValue(array &$identifiers, string $name = null): mixed
{
if (isset($identifiers[$name])) {
if (null !== $name && isset($identifiers[$name])) {
$value = $identifiers[$name];
unset($identifiers[$name]);

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

/**
* @return \ApiPlatform\Metadata\Link[]|array
*/
private function getOperationLinks(Operation $operation = null): array
{
if ($operation instanceof GraphQlOperation) {
Expand All @@ -114,22 +119,4 @@ private function getOperationLinks(Operation $operation = null): array

return [];
}

private function getLinksHandler(Operation $operation): ?callable
{
if (!($options = $operation->getStateOptions()) || !method_exists($options, 'getHandleLinks') || null === $options->getHandleLinks()) {
return null;
}

$handleLinks = $options->getHandleLinks(); // @phpstan-ignore-line method_exists called above
if (\is_callable($handleLinks)) {
return $handleLinks;
}

if ($this->handleLinksLocator && \is_string($handleLinks) && $this->handleLinksLocator->has($handleLinks)) {
return [$this->handleLinksLocator->get($handleLinks), 'handleLinks'];
}

throw new RuntimeException(sprintf('Could not find handleLinks service "%s"', $handleLinks));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public function create(string $resourceClass): ResourceMetadataCollection

private function addDefaults(Operation $operation): Operation
{
$options = $operation->getStateOptions() ?: new Options();
if ($options instanceof Options && null === $options->getHandleLinks()) {
$options = $options->withHandleLinks('api_platform.doctrine.odm.links_handler');
$operation = $operation->withStateOptions($options);
}

if (null === $operation->getProvider()) {
$operation = $operation->withProvider($this->getProvider($operation));
}
Expand Down
5 changes: 4 additions & 1 deletion src/Doctrine/Odm/State/CollectionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Doctrine\Odm\State;

use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
use ApiPlatform\Doctrine\Odm\Extension\AggregationCollectionExtensionInterface;
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultCollectionExtensionInterface;
use ApiPlatform\Exception\RuntimeException;
Expand All @@ -29,15 +30,17 @@
*/
final class CollectionProvider implements ProviderInterface
{
use LinksHandlerLocatorTrait;
use LinksHandlerTrait;

/**
* @param AggregationCollectionExtensionInterface[] $collectionExtensions
*/
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
{
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
$this->handleLinksLocator = $handleLinksLocator;
$this->managerRegistry = $managerRegistry;
}

public function provide(Operation $operation, array $uriVariables = [], array $context = []): iterable
Expand Down
5 changes: 4 additions & 1 deletion src/Doctrine/Odm/State/ItemProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Doctrine\Odm\State;

use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
use ApiPlatform\Doctrine\Odm\Extension\AggregationItemExtensionInterface;
use ApiPlatform\Doctrine\Odm\Extension\AggregationResultItemExtensionInterface;
use ApiPlatform\Exception\RuntimeException;
Expand All @@ -32,15 +33,17 @@
*/
final class ItemProvider implements ProviderInterface
{
use LinksHandlerLocatorTrait;
use LinksHandlerTrait;

/**
* @param AggregationItemExtensionInterface[] $itemExtensions
*/
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
{
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
$this->handleLinksLocator = $handleLinksLocator;
$this->managerRegistry = $managerRegistry;
}

public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object
Expand Down
3 changes: 3 additions & 0 deletions src/Doctrine/Odm/State/LinksHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Doctrine\ODM\MongoDB\Aggregation\Builder;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\Persistence\ManagerRegistry;

/**
* @internal
Expand All @@ -28,6 +29,8 @@ trait LinksHandlerTrait
{
use CommonLinksHandlerTrait;

private ManagerRegistry $managerRegistry;

private function handleLinks(Builder $aggregationBuilder, array $identifiers, array $context, string $resourceClass, Operation $operation = null): void
{
if (!$identifiers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ private function addDefaults(Operation $operation): Operation
$operation = $operation->withProvider($this->getProvider($operation));
}

$options = $operation->getStateOptions() ?: new Options();
if ($options instanceof Options && null === $options->getHandleLinks()) {
$options = $options->withHandleLinks('api_platform.doctrine.orm.links_handler');
$operation = $operation->withStateOptions($options);
}

if (null === $operation->getProcessor()) {
$operation = $operation->withProcessor($this->getProcessor($operation));
}
Expand Down
5 changes: 4 additions & 1 deletion src/Doctrine/Orm/State/CollectionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Doctrine\Orm\State;

use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
Expand All @@ -32,15 +33,17 @@
*/
final class CollectionProvider implements ProviderInterface
{
use LinksHandlerLocatorTrait;
use LinksHandlerTrait;

/**
* @param QueryCollectionExtensionInterface[] $collectionExtensions
*/
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $collectionExtensions = [], ContainerInterface $handleLinksLocator = null)
{
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
$this->handleLinksLocator = $handleLinksLocator;
$this->managerRegistry = $managerRegistry;
}

public function provide(Operation $operation, array $uriVariables = [], array $context = []): iterable
Expand Down
5 changes: 4 additions & 1 deletion src/Doctrine/Orm/State/ItemProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace ApiPlatform\Doctrine\Orm\State;

use ApiPlatform\Doctrine\Common\State\LinksHandlerLocatorTrait;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryResultItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
Expand All @@ -32,15 +33,17 @@
*/
final class ItemProvider implements ProviderInterface
{
use LinksHandlerLocatorTrait;
use LinksHandlerTrait;

/**
* @param QueryItemExtensionInterface[] $itemExtensions
*/
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, private readonly ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry, private readonly iterable $itemExtensions = [], ContainerInterface $handleLinksLocator = null)
{
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
$this->handleLinksLocator = $handleLinksLocator;
$this->managerRegistry = $managerRegistry;
}

public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?object
Expand Down
37 changes: 37 additions & 0 deletions src/Doctrine/Orm/State/LinksHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Doctrine\Orm\State;

use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

final class LinksHandler implements LinksHandlerInterface
{
use LinksHandlerTrait {
handleLinks as private handle;
}

public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory, ManagerRegistry $managerRegistry)
{
$this->resourceMetadataCollectionFactory = $resourceMetadataCollectionFactory;
$this->managerRegistry = $managerRegistry;
}

public function handleLinks(QueryBuilder $queryBuilder, array $uriVariables, QueryNameGeneratorInterface $queryNameGenerator, array $context): void
{
$this->handle($queryBuilder, $uriVariables, $queryNameGenerator, $context, $context['entityClass'], $context['operation']);
}
}
7 changes: 5 additions & 2 deletions src/Doctrine/Orm/State/LinksHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
namespace ApiPlatform\Doctrine\Orm\State;

use ApiPlatform\Doctrine\Common\State\LinksHandlerTrait as CommonLinksHandlerTrait;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

/**
* @internal
Expand All @@ -27,7 +28,9 @@ trait LinksHandlerTrait
{
use CommonLinksHandlerTrait;

private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, QueryNameGenerator $queryNameGenerator, array $context, string $entityClass, Operation $operation): void
private ManagerRegistry $managerRegistry;

private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, QueryNameGeneratorInterface $queryNameGenerator, array $context, string $entityClass, Operation $operation): void
{
if (!$identifiers) {
return;
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Bundle/Resources/config/doctrine_mongodb_odm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@
<argument type="service" id="doctrine_mongodb" />
<argument type="service" id="api_platform.doctrine.odm.metadata.resource.metadata_collection_factory.inner" />
</service>

<service id="api_platform.doctrine.odm.links_handler" class="ApiPlatform\Doctrine\Odm\State\LinksHandler">
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
<argument type="service" id="doctrine_mongodb" />

<tag name="api_platform.doctrine.odm.links_handler" key="api_platform.doctrine.odm.links_handler" />
</service>
</services>

</container>
6 changes: 6 additions & 0 deletions src/Symfony/Bundle/Resources/config/doctrine_orm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@
<argument type="service" id="api_platform.doctrine.orm.metadata.resource.link_factory.inner" />
</service>

<service id="api_platform.doctrine.orm.links_handler" class="ApiPlatform\Doctrine\Orm\State\LinksHandler">
<argument type="service" id="api_platform.metadata.resource.metadata_collection_factory" />
<argument type="service" id="doctrine" />

<tag name="api_platform.doctrine.orm.links_handler" key="api_platform.doctrine.orm.links_handler" />
</service>
</services>

</container>

0 comments on commit a749fe8

Please sign in to comment.