vendor/gedmo/doctrine-extensions/src/Mapping/ExtensionMetadataFactory.php line 134

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Doctrine Behavioral Extensions package.
  4.  * (c) Gediminas Morkevicius <gediminas.morkevicius@gmail.com> http://www.gediminasm.org
  5.  * For the full copyright and license information, please view the LICENSE
  6.  * file that was distributed with this source code.
  7.  */
  8. namespace Gedmo\Mapping;
  9. use Doctrine\Bundle\DoctrineBundle\Mapping\MappingDriver as DoctrineBundleMappingDriver;
  10. use Doctrine\Common\Annotations\Reader;
  11. use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as DocumentClassMetadata;
  12. use Doctrine\ORM\Mapping\ClassMetadataInfo as EntityClassMetadata;
  13. use Doctrine\Persistence\Mapping\ClassMetadata;
  14. use Doctrine\Persistence\Mapping\Driver\DefaultFileLocator;
  15. use Doctrine\Persistence\Mapping\Driver\MappingDriver;
  16. use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
  17. use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
  18. use Doctrine\Persistence\ObjectManager;
  19. use Gedmo\Exception\RuntimeException;
  20. use Gedmo\Mapping\Driver\AnnotationDriverInterface;
  21. use Gedmo\Mapping\Driver\AttributeAnnotationReader;
  22. use Gedmo\Mapping\Driver\AttributeDriverInterface;
  23. use Gedmo\Mapping\Driver\AttributeReader;
  24. use Gedmo\Mapping\Driver\Chain;
  25. use Gedmo\Mapping\Driver\File as FileDriver;
  26. use Psr\Cache\CacheItemPoolInterface;
  27. /**
  28.  * The extension metadata factory is responsible for extension driver
  29.  * initialization and fully reading the extension metadata
  30.  *
  31.  * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  32.  *
  33.  * @final since gedmo/doctrine-extensions 3.11
  34.  */
  35. class ExtensionMetadataFactory
  36. {
  37.     /**
  38.      * Extension driver
  39.      *
  40.      * @var Driver
  41.      */
  42.     protected $driver;
  43.     /**
  44.      * Object manager, entity or document
  45.      *
  46.      * @var ObjectManager
  47.      */
  48.     protected $objectManager;
  49.     /**
  50.      * Extension namespace
  51.      *
  52.      * @var string
  53.      */
  54.     protected $extensionNamespace;
  55.     /**
  56.      * Custom annotation reader
  57.      *
  58.      * @var Reader|AttributeReader|object
  59.      */
  60.     protected $annotationReader;
  61.     /**
  62.      * @var CacheItemPoolInterface|null
  63.      */
  64.     private $cacheItemPool;
  65.     /**
  66.      * @param Reader|AttributeReader|object $annotationReader
  67.      */
  68.     public function __construct(ObjectManager $objectManagerstring $extensionNamespaceobject $annotationReader, ?CacheItemPoolInterface $cacheItemPool null)
  69.     {
  70.         if (!$annotationReader instanceof Reader && !$annotationReader instanceof AttributeReader) {
  71.             trigger_deprecation(
  72.                 'gedmo/doctrine-extensions',
  73.                 '3.11',
  74.                 'Providing an annotation reader which does not implement %s or is not an instance of %s to %s is deprecated.',
  75.                 Reader::class,
  76.                 AttributeReader::class,
  77.                 static::class
  78.             );
  79.         }
  80.         $this->objectManager $objectManager;
  81.         $this->annotationReader $annotationReader;
  82.         $this->extensionNamespace $extensionNamespace;
  83.         $omDriver $objectManager->getConfiguration()->getMetadataDriverImpl();
  84.         $this->driver $this->getDriver($omDriver);
  85.         $this->cacheItemPool $cacheItemPool;
  86.     }
  87.     /**
  88.      * Reads extension metadata
  89.      *
  90.      * @param ClassMetadata&(DocumentClassMetadata|EntityClassMetadata) $meta
  91.      *
  92.      * @return array<string, mixed> the metatada configuration
  93.      */
  94.     public function getExtensionMetadata($meta)
  95.     {
  96.         if ($meta->isMappedSuperclass) {
  97.             return []; // ignore mappedSuperclasses for now
  98.         }
  99.         $config = [];
  100.         $cmf $this->objectManager->getMetadataFactory();
  101.         $useObjectName $meta->getName();
  102.         // collect metadata from inherited classes
  103.         if (null !== $meta->reflClass) {
  104.             foreach (array_reverse(class_parents($meta->getName())) as $parentClass) {
  105.                 // read only inherited mapped classes
  106.                 if ($cmf->hasMetadataFor($parentClass) || !$cmf->isTransient($parentClass)) {
  107.                     assert(class_exists($parentClass));
  108.                     $class $this->objectManager->getClassMetadata($parentClass);
  109.                     assert($class instanceof DocumentClassMetadata || $class instanceof EntityClassMetadata);
  110.                     $this->driver->readExtendedMetadata($class$config);
  111.                     $isBaseInheritanceLevel = !$class->isInheritanceTypeNone()
  112.                         && [] === $class->parentClasses
  113.                         && [] !== $config
  114.                     ;
  115.                     if ($isBaseInheritanceLevel) {
  116.                         $useObjectName $class->getName();
  117.                     }
  118.                 }
  119.             }
  120.             $this->driver->readExtendedMetadata($meta$config);
  121.         }
  122.         if ([] !== $config) {
  123.             $config['useObjectClass'] = $useObjectName;
  124.         }
  125.         $this->storeConfiguration($meta->getName(), $config);
  126.         return $config;
  127.     }
  128.     /**
  129.      * Get the cache id
  130.      *
  131.      * @param string $className
  132.      * @param string $extensionNamespace
  133.      *
  134.      * @return string
  135.      */
  136.     public static function getCacheId($className$extensionNamespace)
  137.     {
  138.         return str_replace('\\''_'$className).'_$'.strtoupper(str_replace('\\''_'$extensionNamespace)).'_CLASSMETADATA';
  139.     }
  140.     /**
  141.      * Get the extended driver instance which will
  142.      * read the metadata required by extension
  143.      *
  144.      * @param MappingDriver $omDriver
  145.      *
  146.      * @throws RuntimeException if driver was not found in extension
  147.      *
  148.      * @return Driver
  149.      */
  150.     protected function getDriver($omDriver)
  151.     {
  152.         if ($omDriver instanceof DoctrineBundleMappingDriver) {
  153.             $omDriver $omDriver->getDriver();
  154.         }
  155.         $driver null;
  156.         $className get_class($omDriver);
  157.         $driverName substr($classNamestrrpos($className'\\') + 1);
  158.         if ($omDriver instanceof MappingDriverChain || 'DriverChain' === $driverName) {
  159.             $driver = new Chain();
  160.             foreach ($omDriver->getDrivers() as $namespace => $nestedOmDriver) {
  161.                 $driver->addDriver($this->getDriver($nestedOmDriver), $namespace);
  162.             }
  163.             if (null !== $omDriver->getDefaultDriver()) {
  164.                 $driver->setDefaultDriver($this->getDriver($omDriver->getDefaultDriver()));
  165.             }
  166.         } else {
  167.             $driverName substr($driverName0strpos($driverName'Driver'));
  168.             $isSimplified false;
  169.             if ('Simplified' === substr($driverName010)) {
  170.                 // support for simplified file drivers
  171.                 $driverName substr($driverName10);
  172.                 $isSimplified true;
  173.             }
  174.             // create driver instance
  175.             $driverClassName $this->extensionNamespace.'\Mapping\Driver\\'.$driverName;
  176.             if (!class_exists($driverClassName)) {
  177.                 $driverClassName $this->extensionNamespace.'\Mapping\Driver\Annotation';
  178.                 if (!class_exists($driverClassName)) {
  179.                     throw new RuntimeException("Failed to fallback to annotation driver: ({$driverClassName}), extension driver was not found.");
  180.                 }
  181.             }
  182.             $driver = new $driverClassName();
  183.             $driver->setOriginalDriver($omDriver);
  184.             if ($driver instanceof FileDriver) {
  185.                 if ($omDriver instanceof MappingDriver) {
  186.                     $driver->setLocator($omDriver->getLocator());
  187.                 // BC for Doctrine 2.2
  188.                 } elseif ($isSimplified) {
  189.                     $driver->setLocator(new SymfonyFileLocator($omDriver->getNamespacePrefixes(), $omDriver->getFileExtension()));
  190.                 } else {
  191.                     $driver->setLocator(new DefaultFileLocator($omDriver->getPaths(), $omDriver->getFileExtension()));
  192.                 }
  193.             }
  194.             if ($driver instanceof AttributeDriverInterface) {
  195.                 if ($this->annotationReader instanceof AttributeReader) {
  196.                     $driver->setAnnotationReader($this->annotationReader);
  197.                 } else {
  198.                     $driver->setAnnotationReader(new AttributeAnnotationReader(new AttributeReader(), $this->annotationReader));
  199.                 }
  200.             } elseif ($driver instanceof AnnotationDriverInterface) {
  201.                 $driver->setAnnotationReader($this->annotationReader);
  202.             }
  203.         }
  204.         return $driver;
  205.     }
  206.     /**
  207.      * @param array<string, mixed> $config
  208.      */
  209.     private function storeConfiguration(string $className, array $config): void
  210.     {
  211.         if (null === $this->cacheItemPool) {
  212.             return;
  213.         }
  214.         // Cache the result, even if it's empty, to prevent re-parsing non-existent annotations.
  215.         $cacheId self::getCacheId($className$this->extensionNamespace);
  216.         $item $this->cacheItemPool->getItem($cacheId);
  217.         $this->cacheItemPool->save($item->set($config));
  218.     }
  219. }