vendor/jms/metadata/src/MetadataFactory.php line 145

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Metadata;
  4. use Metadata\Cache\CacheInterface;
  5. use Metadata\Driver\AdvancedDriverInterface;
  6. use Metadata\Driver\DriverInterface;
  7. class MetadataFactory implements AdvancedMetadataFactoryInterface
  8. {
  9.     /**
  10.      * @var DriverInterface
  11.      */
  12.     private $driver;
  13.     /**
  14.      * @var CacheInterface
  15.      */
  16.     private $cache;
  17.     /**
  18.      * @var ClassMetadata[]
  19.      */
  20.     private $loadedMetadata = [];
  21.     /**
  22.      * @var ClassMetadata[]
  23.      */
  24.     private $loadedClassMetadata = [];
  25.     /**
  26.      * @var string|null
  27.      */
  28.     private $hierarchyMetadataClass;
  29.     /**
  30.      * @var bool
  31.      */
  32.     private $includeInterfaces false;
  33.     /**
  34.      * @var bool
  35.      */
  36.     private $debug false;
  37.     public function __construct(DriverInterface $driver, ?string $hierarchyMetadataClass 'Metadata\ClassHierarchyMetadata'bool $debug false)
  38.     {
  39.         $this->driver $driver;
  40.         $this->hierarchyMetadataClass $hierarchyMetadataClass;
  41.         $this->debug $debug;
  42.     }
  43.     public function setIncludeInterfaces(bool $include): void
  44.     {
  45.         $this->includeInterfaces $include;
  46.     }
  47.     public function setCache(CacheInterface $cache): void
  48.     {
  49.         $this->cache $cache;
  50.     }
  51.     /**
  52.      * {@inheritDoc}
  53.      */
  54.     public function getMetadataForClass(string $className)
  55.     {
  56.         if (isset($this->loadedMetadata[$className])) {
  57.             return $this->filterNullMetadata($this->loadedMetadata[$className]);
  58.         }
  59.         $metadata null;
  60.         foreach ($this->getClassHierarchy($className) as $class) {
  61.             if (isset($this->loadedClassMetadata[$name $class->getName()])) {
  62.                 if (null !== $classMetadata $this->filterNullMetadata($this->loadedClassMetadata[$name])) {
  63.                     $this->addClassMetadata($metadata$classMetadata);
  64.                 }
  65.                 continue;
  66.             }
  67.             // check the cache
  68.             if (null !== $this->cache) {
  69.                 if (($classMetadata $this->cache->load($class->getName())) instanceof NullMetadata) {
  70.                     $this->loadedClassMetadata[$name] = $classMetadata;
  71.                     continue;
  72.                 }
  73.                 if (null !== $classMetadata) {
  74.                     if (!$classMetadata instanceof ClassMetadata) {
  75.                         throw new \LogicException(sprintf(
  76.                             'The cache must return instances of ClassMetadata for class %s, but got %s.',
  77.                             $className,
  78.                             var_export($classMetadatatrue)
  79.                         ));
  80.                     }
  81.                     if ($this->debug && !$classMetadata->isFresh()) {
  82.                         $this->cache->evict($classMetadata->name);
  83.                     } else {
  84.                         $this->loadedClassMetadata[$name] = $classMetadata;
  85.                         $this->addClassMetadata($metadata$classMetadata);
  86.                         continue;
  87.                     }
  88.                 }
  89.             }
  90.             // load from source
  91.             if (null !== $classMetadata $this->driver->loadMetadataForClass($class)) {
  92.                 $this->loadedClassMetadata[$name] = $classMetadata;
  93.                 $this->addClassMetadata($metadata$classMetadata);
  94.                 if (null !== $this->cache) {
  95.                     $this->cache->put($classMetadata);
  96.                 }
  97.                 continue;
  98.             }
  99.             if (null !== $this->cache && !$this->debug) {
  100.                 $this->cache->put(new NullMetadata($class->getName()));
  101.             }
  102.         }
  103.         if (null === $metadata) {
  104.             $metadata = new NullMetadata($className);
  105.         }
  106.         return $this->filterNullMetadata($this->loadedMetadata[$className] = $metadata);
  107.     }
  108.     /**
  109.      * {@inheritDoc}
  110.      */
  111.     public function getAllClassNames(): array
  112.     {
  113.         if (!$this->driver instanceof AdvancedDriverInterface) {
  114.             throw new \RuntimeException(
  115.                 sprintf('Driver "%s" must be an instance of "AdvancedDriverInterface".'get_class($this->driver))
  116.             );
  117.         }
  118.         return $this->driver->getAllClassNames();
  119.     }
  120.     /**
  121.      * @param MergeableInterface|ClassHierarchyMetadata $metadata
  122.      */
  123.     private function addClassMetadata(&$metadataClassMetadata $toAdd): void
  124.     {
  125.         if ($toAdd instanceof MergeableInterface) {
  126.             if (null === $metadata) {
  127.                 $metadata = clone $toAdd;
  128.             } else {
  129.                 $metadata->merge($toAdd);
  130.             }
  131.         } else {
  132.             if (null === $metadata) {
  133.                 $class $this->hierarchyMetadataClass;
  134.                 $metadata = new $class();
  135.             }
  136.             $metadata->addClassMetadata($toAdd);
  137.         }
  138.     }
  139.     /**
  140.      * @return \ReflectionClass[]
  141.      */
  142.     private function getClassHierarchy(string $class): array
  143.     {
  144.         $classes = [];
  145.         $refl = new \ReflectionClass($class);
  146.         do {
  147.             $classes[] = $refl;
  148.             $refl $refl->getParentClass();
  149.         } while (false !== $refl);
  150.         $classes array_reverse($classesfalse);
  151.         if (!$this->includeInterfaces) {
  152.             return $classes;
  153.         }
  154.         $addedInterfaces = [];
  155.         $newHierarchy = [];
  156.         foreach ($classes as $class) {
  157.             foreach ($class->getInterfaces() as $interface) {
  158.                 if (isset($addedInterfaces[$interface->getName()])) {
  159.                     continue;
  160.                 }
  161.                 $addedInterfaces[$interface->getName()] = true;
  162.                 $newHierarchy[] = $interface;
  163.             }
  164.             $newHierarchy[] = $class;
  165.         }
  166.         return $newHierarchy;
  167.     }
  168.     /**
  169.      * @param ClassMetadata|ClassHierarchyMetadata|MergeableInterface $metadata
  170.      *
  171.      * @return ClassMetadata|ClassHierarchyMetadata|MergeableInterface
  172.      */
  173.     private function filterNullMetadata($metadata null)
  174.     {
  175.         return !$metadata instanceof NullMetadata $metadata null;
  176.     }
  177. }