diff --git a/CHANGELOG.md b/CHANGELOG.md index ea079941e..77172c813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ a release. --- ## [Unreleased] +### Fixed +- Mapping Driver: Configure usage separately with Doctrine `.orm.xml` -> `.gedmo.xml` files, also add an alternative option - force the use of AttributeReader and ignore the configuration of the Doctrine chain driver (#2613) ## [3.16.1] ### Fixed diff --git a/src/Mapping/Driver/File.php b/src/Mapping/Driver/File.php index 116bd1a8d..365cefe1e 100644 --- a/src/Mapping/Driver/File.php +++ b/src/Mapping/Driver/File.php @@ -120,20 +120,56 @@ abstract protected function _loadMappingFile($file); */ protected function _getMapping($className) { - // try loading mapping from original driver first $mapping = null; - if (null !== $this->_originalDriver) { - if ($this->_originalDriver instanceof FileDriver) { - $mapping = $this->_originalDriver->getElement($className); - } + $separatedFile = strpos($this->locator->getFileExtension(), '.gedmo') === 0; + + if($separatedFile){ + // try loading mapping from gedmo driver first + $mapping = $this->getMappingFromGedmoFileDriver($className); } - // if no mapping found try to load mapping file again + // if no mapping found try to load mapping file from original driver again if (null === $mapping) { - $yaml = $this->_loadMappingFile($this->locator->findMappingFile($className)); - $mapping = $yaml[$className]; + // read .orm.xml + $mapping = $this->getMappingFromOriginalDriver($className); + } + if (!$separatedFile && null === $mapping) { + // if no mapping found try to load mapping file again + $mapping = $this->getMappingFromGedmoFileDriver($className); + } + + return $mapping; + } + /** + * Tries to get a mapping for a given class from gedmo driver. + * + * @param string $className + * + * @return array|object|null + */ + private function getMappingFromGedmoFileDriver($className){ + if(!$this->locator->fileExists($className)){ + return null; } + $mapping = $this->_loadMappingFile($this->locator->findMappingFile($className)); + return $mapping[$className] ?? null; + } + + /** + * Tries to get a mapping for a given class from original doctrine driver. + * + * @param string $className + * + * @return array|object|null + */ + private function getMappingFromOriginalDriver($className){ + $mapping = null; + if (null !== $this->_originalDriver) { + if ($this->_originalDriver instanceof FileDriver) { + $mapping = $this->_originalDriver->getElement($className); + } + } return $mapping; } diff --git a/src/Mapping/ExtensionMetadataFactory.php b/src/Mapping/ExtensionMetadataFactory.php index ccfd4fcd1..23ca7d600 100644 --- a/src/Mapping/ExtensionMetadataFactory.php +++ b/src/Mapping/ExtensionMetadataFactory.php @@ -15,6 +15,7 @@ use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as DocumentClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata as EntityClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataInfo as LegacyEntityClassMetadata; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\Driver\DefaultFileLocator; use Doctrine\Persistence\Mapping\Driver\MappingDriver; @@ -70,12 +71,24 @@ class ExtensionMetadataFactory private ?CacheItemPoolInterface $cacheItemPool = null; + /** + * Ignore doctrine driver class and force use attribute reader for gedmo properties + * @var bool + */ + private $forceUseAttributeReader; + + /** + * Search mapping in .gedmo.xml and does not use doctrine *.orm.xml or *.dcm.xml file + * @var bool + */ + private $separateXmlMapping; + /** * @param Reader|AttributeReader|object|null $annotationReader * * @note Providing any object as the third argument is deprecated, as of 4.0 an {@see AttributeReader} will be required */ - public function __construct(ObjectManager $objectManager, string $extensionNamespace, ?object $annotationReader = null, ?CacheItemPoolInterface $cacheItemPool = null) + public function __construct(ObjectManager $objectManager, string $extensionNamespace, ?object $annotationReader = null, ?CacheItemPoolInterface $cacheItemPool = null, bool $forceUseAttributeReader = false, bool $separateXmlMapping = false) { if (null !== $annotationReader) { if ($annotationReader instanceof Reader) { @@ -101,6 +114,9 @@ public function __construct(ObjectManager $objectManager, string $extensionNames $this->objectManager = $objectManager; $this->annotationReader = $annotationReader; $this->extensionNamespace = $extensionNamespace; + $this->forceUseAttributeReader = $forceUseAttributeReader; + $this->separateXmlMapping = $separateXmlMapping; + $omDriver = $objectManager->getConfiguration()->getMetadataDriverImpl(); $this->driver = $this->getDriver($omDriver); $this->cacheItemPool = $cacheItemPool; @@ -184,6 +200,10 @@ public static function getCacheId($className, $extensionNamespace) return str_replace('\\', '_', $className).'_$'.strtoupper(str_replace('\\', '_', $extensionNamespace)).'_CLASSMETADATA'; } + private function getFileExtension($fileExtension) + { + return $this->separateXmlMapping ? str_replace(['.orm.','.dcm.'], '.gedmo.', $fileExtension) : $fileExtension; + } /** * Get the extended driver instance which will * read the metadata required by extension @@ -205,11 +225,12 @@ protected function getDriver($omDriver) $driverName = substr($className, strrpos($className, '\\') + 1); if ($omDriver instanceof MappingDriverChain || 'DriverChain' === $driverName) { $driver = new Chain(); + $attributeDriver = $this->forceUseAttributeReader ? new AttributeDriver([]) : null; foreach ($omDriver->getDrivers() as $namespace => $nestedOmDriver) { - $driver->addDriver($this->getDriver($nestedOmDriver), $namespace); + $driver->addDriver($this->getDriver($attributeDriver ?? $nestedOmDriver), $namespace); } if (null !== $omDriver->getDefaultDriver()) { - $driver->setDefaultDriver($this->getDriver($omDriver->getDefaultDriver())); + $driver->setDefaultDriver($this->getDriver($attributeDriver ?? $omDriver->getDefaultDriver())); } } else { $driverName = substr($driverName, 0, strpos($driverName, 'Driver')); @@ -243,12 +264,14 @@ protected function getDriver($omDriver) $driver->setOriginalDriver($omDriver); if ($driver instanceof FileDriver) { if ($omDriver instanceof MappingDriver) { - $driver->setLocator($omDriver->getLocator()); + $locator = clone $omDriver->getLocator(); + $locator->setFileExtension($this->getFileExtension( $locator->getFileExtension())); + $driver->setLocator($locator); // BC for Doctrine 2.2 } elseif ($isSimplified) { - $driver->setLocator(new SymfonyFileLocator($omDriver->getNamespacePrefixes(), $omDriver->getFileExtension())); + $driver->setLocator(new SymfonyFileLocator($omDriver->getNamespacePrefixes(), $this->getFileExtension( $omDriver->getFileExtension()))); } else { - $driver->setLocator(new DefaultFileLocator($omDriver->getPaths(), $omDriver->getFileExtension())); + $driver->setLocator(new DefaultFileLocator($omDriver->getPaths(), $this->getFileExtension( $omDriver->getFileExtension()))); } } diff --git a/src/Mapping/MappedEventSubscriber.php b/src/Mapping/MappedEventSubscriber.php index 67d110714..47d9d496f 100644 --- a/src/Mapping/MappedEventSubscriber.php +++ b/src/Mapping/MappedEventSubscriber.php @@ -99,12 +99,35 @@ abstract class MappedEventSubscriber implements EventSubscriber private ?ClockInterface $clock = null; + /** + * Ignore doctrine driver class and force use attribute reader for gedmo properties + * @var bool + */ + private $forceUseAttributeReader = false; + + /** + * Search mapping in .gedmo.xml and does not use doctrine *.orm.xml or *.dcm.xml file + * @var bool + */ + private $separateXmlMapping = false; + + public function __construct() { $parts = explode('\\', $this->getNamespace()); $this->name = end($parts); } + + public function setForceUseAttributeReader(bool $forceUseAttributeReader) { + $this->forceUseAttributeReader = $forceUseAttributeReader; + } + public function setSeparateXmlMapping(bool $separateXmlMapping) { + $this->separateXmlMapping = $separateXmlMapping; + } + + + /** * Get the configuration for specific object class * if cache driver is present it scans it also @@ -183,7 +206,9 @@ public function getExtensionMetadataFactory(ObjectManager $objectManager) $objectManager, $this->getNamespace(), $this->annotationReader, - $this->getCacheItemPool($objectManager) + $this->getCacheItemPool($objectManager), + $this->forceUseAttributeReader, + $this->separateXmlMapping ); }