vendor/api-platform/core/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php line 51

  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace ApiPlatform\GraphQl\Resolver\Factory;
  12. use ApiPlatform\GraphQl\Resolver\QueryCollectionResolverInterface;
  13. use ApiPlatform\GraphQl\Resolver\Stage\ReadStageInterface;
  14. use ApiPlatform\GraphQl\Resolver\Stage\SecurityPostDenormalizeStageInterface;
  15. use ApiPlatform\GraphQl\Resolver\Stage\SecurityStageInterface;
  16. use ApiPlatform\GraphQl\Resolver\Stage\SerializeStageInterface;
  17. use ApiPlatform\Metadata\GraphQl\Operation;
  18. use ApiPlatform\Util\CloneTrait;
  19. use GraphQL\Type\Definition\ResolveInfo;
  20. use Psr\Container\ContainerInterface;
  21. /**
  22.  * Creates a function retrieving a collection to resolve a GraphQL query or a field returned by a mutation.
  23.  *
  24.  * @author Alan Poulain <contact@alanpoulain.eu>
  25.  * @author Kévin Dunglas <dunglas@gmail.com>
  26.  * @author Vincent Chalamon <vincentchalamon@gmail.com>
  27.  */
  28. final class CollectionResolverFactory implements ResolverFactoryInterface
  29. {
  30.     use CloneTrait;
  31.     public function __construct(private readonly ReadStageInterface $readStage, private readonly SecurityStageInterface $securityStage, private readonly SecurityPostDenormalizeStageInterface $securityPostDenormalizeStage, private readonly SerializeStageInterface $serializeStage, private readonly ContainerInterface $queryResolverLocator)
  32.     {
  33.     }
  34.     public function __invoke(?string $resourceClass null, ?string $rootClass null, ?Operation $operation null): callable
  35.     {
  36.         return function (?array $source, array $args$contextResolveInfo $info) use ($resourceClass$rootClass$operation): ?array {
  37.             // If authorization has failed for a relation field (e.g. via ApiProperty security), the field is not present in the source: null can be returned directly to ensure the collection isn't in the response.
  38.             if (null === $resourceClass || null === $rootClass || (null !== $source && !\array_key_exists($info->fieldName$source))) {
  39.                 return null;
  40.             }
  41.             $resolverContext = ['source' => $source'args' => $args'info' => $info'is_collection' => true'is_mutation' => false'is_subscription' => false];
  42.             $collection = ($this->readStage)($resourceClass$rootClass$operation$resolverContext);
  43.             if (!is_iterable($collection)) {
  44.                 throw new \LogicException('Collection from read stage should be iterable.');
  45.             }
  46.             $queryResolverId $operation->getResolver();
  47.             if (null !== $queryResolverId) {
  48.                 /** @var QueryCollectionResolverInterface $queryResolver */
  49.                 $queryResolver $this->queryResolverLocator->get($queryResolverId);
  50.                 $collection $queryResolver($collection$resolverContext);
  51.             }
  52.             // Only perform security stage on the top-level query
  53.             if (null === $source) {
  54.                 ($this->securityStage)($resourceClass$operation$resolverContext + [
  55.                     'extra_variables' => [
  56.                         'object' => $collection,
  57.                     ],
  58.                 ]);
  59.                 ($this->securityPostDenormalizeStage)($resourceClass$operation$resolverContext + [
  60.                     'extra_variables' => [
  61.                         'object' => $collection,
  62.                         'previous_object' => $this->clone($collection),
  63.                     ],
  64.                 ]);
  65.             }
  66.             return ($this->serializeStage)($collection$resourceClass$operation$resolverContext);
  67.         };
  68.     }
  69. }