vendor/api-platform/core/src/Api/ResourceClassResolver.php line 94

  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\Api;
  12. use ApiPlatform\Exception\InvalidArgumentException;
  13. use ApiPlatform\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
  14. use ApiPlatform\Util\ClassInfoTrait;
  15. /**
  16.  * {@inheritdoc}
  17.  *
  18.  * @author Kévin Dunglas <dunglas@gmail.com>
  19.  * @author Samuel ROZE <samuel.roze@gmail.com>
  20.  */
  21. final class ResourceClassResolver implements ResourceClassResolverInterface
  22. {
  23.     use ClassInfoTrait;
  24.     private array $localIsResourceClassCache = [];
  25.     private array $localMostSpecificResourceClassCache = [];
  26.     public function __construct(private readonly ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory)
  27.     {
  28.     }
  29.     /**
  30.      * {@inheritdoc}
  31.      */
  32.     public function getResourceClass(mixed $valuestring $resourceClass nullbool $strict false): string
  33.     {
  34.         if ($strict && null === $resourceClass) {
  35.             throw new InvalidArgumentException('Strict checking is only possible when resource class is specified.');
  36.         }
  37.         $objectClass \is_object($value) ? $this->getObjectClass($value) : null;
  38.         $actualClass = ($objectClass && (!$value instanceof \Traversable || $this->isResourceClass($objectClass))) ? $this->getObjectClass($value) : null;
  39.         if (null === $actualClass && null === $resourceClass) {
  40.             throw new InvalidArgumentException('Resource type could not be determined. Resource class must be specified.');
  41.         }
  42.         if (null !== $actualClass && !$this->isResourceClass($actualClass)) {
  43.             throw new InvalidArgumentException(sprintf('No resource class found for object of type "%s".'$actualClass));
  44.         }
  45.         if (null !== $resourceClass && !$this->isResourceClass($resourceClass)) {
  46.             throw new InvalidArgumentException(sprintf('Specified class "%s" is not a resource class.'$resourceClass));
  47.         }
  48.         if ($strict && null !== $actualClass && !is_a($actualClass$resourceClasstrue)) {
  49.             throw new InvalidArgumentException(sprintf('Object of type "%s" does not match "%s" resource class.'$actualClass$resourceClass));
  50.         }
  51.         $targetClass $actualClass ?? $resourceClass;
  52.         if (isset($this->localMostSpecificResourceClassCache[$targetClass])) {
  53.             return $this->localMostSpecificResourceClassCache[$targetClass];
  54.         }
  55.         $mostSpecificResourceClass null;
  56.         foreach ($this->resourceNameCollectionFactory->create() as $resourceClassName) {
  57.             if (!is_a($targetClass$resourceClassNametrue)) {
  58.                 continue;
  59.             }
  60.             if (null === $mostSpecificResourceClass || is_subclass_of($resourceClassName$mostSpecificResourceClass)) {
  61.                 $mostSpecificResourceClass $resourceClassName;
  62.             }
  63.         }
  64.         if (null === $mostSpecificResourceClass) {
  65.             throw new \LogicException('Unexpected execution flow.');
  66.         }
  67.         $this->localMostSpecificResourceClassCache[$targetClass] = $mostSpecificResourceClass;
  68.         return $mostSpecificResourceClass;
  69.     }
  70.     /**
  71.      * {@inheritdoc}
  72.      */
  73.     public function isResourceClass(string $type): bool
  74.     {
  75.         if (isset($this->localIsResourceClassCache[$type])) {
  76.             return $this->localIsResourceClassCache[$type];
  77.         }
  78.         foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
  79.             if (is_a($type$resourceClasstrue)) {
  80.                 return $this->localIsResourceClassCache[$type] = true;
  81.             }
  82.         }
  83.         return $this->localIsResourceClassCache[$type] = false;
  84.     }
  85. }