From bf6655a534a6775d30cafa67bd801276bda1d98d Mon Sep 17 00:00:00 2001 From: polo Date: Tue, 13 Aug 2024 23:45:21 +0200 Subject: =?UTF-8?q?VERSION=200.2=20doctrine=20ORM=20et=20entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Persistence/AbstractManagerRegistry.php | 269 +++++++++++ .../src/Persistence/ConnectionRegistry.php | 41 ++ .../src/Persistence/Event/LifecycleEventArgs.php | 54 +++ .../Event/LoadClassMetadataEventArgs.php | 61 +++ .../src/Persistence/Event/ManagerEventArgs.php | 39 ++ .../src/Persistence/Event/OnClearEventArgs.php | 42 ++ .../src/Persistence/Event/PreUpdateEventArgs.php | 110 +++++ .../src/Persistence/ManagerRegistry.php | 89 ++++ .../Mapping/AbstractClassMetadataFactory.php | 499 +++++++++++++++++++++ .../src/Persistence/Mapping/ClassMetadata.php | 141 ++++++ .../Persistence/Mapping/ClassMetadataFactory.php | 61 +++ .../Mapping/Driver/ColocatedMappingDriver.php | 212 +++++++++ .../Mapping/Driver/DefaultFileLocator.php | 175 ++++++++ .../src/Persistence/Mapping/Driver/FileDriver.php | 213 +++++++++ .../src/Persistence/Mapping/Driver/FileLocator.php | 52 +++ .../Persistence/Mapping/Driver/MappingDriver.php | 43 ++ .../Mapping/Driver/MappingDriverChain.php | 142 ++++++ .../src/Persistence/Mapping/Driver/PHPDriver.php | 49 ++ .../Persistence/Mapping/Driver/StaticPHPDriver.php | 132 ++++++ .../Mapping/Driver/SymfonyFileLocator.php | 265 +++++++++++ .../src/Persistence/Mapping/MappingException.php | 88 ++++ .../Persistence/Mapping/ProxyClassNameResolver.php | 19 + .../src/Persistence/Mapping/ReflectionService.php | 75 ++++ .../Mapping/RuntimeReflectionService.php | 111 +++++ .../Mapping/StaticReflectionService.php | 78 ++++ .../src/Persistence/NotifyPropertyChanged.php | 22 + .../persistence/src/Persistence/ObjectManager.php | 145 ++++++ .../src/Persistence/ObjectManagerDecorator.php | 92 ++++ .../src/Persistence/ObjectRepository.php | 73 +++ .../src/Persistence/PropertyChangedListener.php | 24 + .../doctrine/persistence/src/Persistence/Proxy.php | 39 ++ .../Reflection/EnumReflectionProperty.php | 181 ++++++++ .../Reflection/RuntimePublicReflectionProperty.php | 61 +++ .../Reflection/RuntimeReflectionProperty.php | 87 ++++ .../TypedNoDefaultReflectionProperty.php | 13 + .../TypedNoDefaultReflectionPropertyBase.php | 68 +++ ...pedNoDefaultRuntimePublicReflectionProperty.php | 15 + 37 files changed, 3880 insertions(+) create mode 100644 vendor/doctrine/persistence/src/Persistence/AbstractManagerRegistry.php create mode 100644 vendor/doctrine/persistence/src/Persistence/ConnectionRegistry.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Event/LifecycleEventArgs.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Event/LoadClassMetadataEventArgs.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Event/ManagerEventArgs.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Event/OnClearEventArgs.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Event/PreUpdateEventArgs.php create mode 100644 vendor/doctrine/persistence/src/Persistence/ManagerRegistry.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadata.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadataFactory.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/MappingException.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/ProxyClassNameResolver.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/ReflectionService.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/RuntimeReflectionService.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Mapping/StaticReflectionService.php create mode 100644 vendor/doctrine/persistence/src/Persistence/NotifyPropertyChanged.php create mode 100644 vendor/doctrine/persistence/src/Persistence/ObjectManager.php create mode 100644 vendor/doctrine/persistence/src/Persistence/ObjectManagerDecorator.php create mode 100644 vendor/doctrine/persistence/src/Persistence/ObjectRepository.php create mode 100644 vendor/doctrine/persistence/src/Persistence/PropertyChangedListener.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Proxy.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/EnumReflectionProperty.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/RuntimePublicReflectionProperty.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/RuntimeReflectionProperty.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultReflectionProperty.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultReflectionPropertyBase.php create mode 100644 vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultRuntimePublicReflectionProperty.php (limited to 'vendor/doctrine/persistence/src') diff --git a/vendor/doctrine/persistence/src/Persistence/AbstractManagerRegistry.php b/vendor/doctrine/persistence/src/Persistence/AbstractManagerRegistry.php new file mode 100644 index 0000000..cc245ba --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/AbstractManagerRegistry.php @@ -0,0 +1,269 @@ + */ + private $connections; + + /** @var array */ + private $managers; + + /** @var string */ + private $defaultConnection; + + /** @var string */ + private $defaultManager; + + /** + * @var string + * @psalm-var class-string + */ + private $proxyInterfaceName; + + /** + * @param array $connections + * @param array $managers + * @psalm-param class-string $proxyInterfaceName + */ + public function __construct( + string $name, + array $connections, + array $managers, + string $defaultConnection, + string $defaultManager, + string $proxyInterfaceName + ) { + $this->name = $name; + $this->connections = $connections; + $this->managers = $managers; + $this->defaultConnection = $defaultConnection; + $this->defaultManager = $defaultManager; + $this->proxyInterfaceName = $proxyInterfaceName; + } + + /** + * Fetches/creates the given services. + * + * A service in this context is connection or a manager instance. + * + * @param string $name The name of the service. + * + * @return object The instance of the given service. + */ + abstract protected function getService(string $name); + + /** + * Resets the given services. + * + * A service in this context is connection or a manager instance. + * + * @param string $name The name of the service. + * + * @return void + */ + abstract protected function resetService(string $name); + + /** + * Gets the name of the registry. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritDoc} + */ + public function getConnection(?string $name = null) + { + if ($name === null) { + $name = $this->defaultConnection; + } + + if (! isset($this->connections[$name])) { + throw new InvalidArgumentException( + sprintf('Doctrine %s Connection named "%s" does not exist.', $this->name, $name) + ); + } + + return $this->getService($this->connections[$name]); + } + + /** + * {@inheritDoc} + */ + public function getConnectionNames() + { + return $this->connections; + } + + /** + * {@inheritDoc} + */ + public function getConnections() + { + $connections = []; + foreach ($this->connections as $name => $id) { + $connections[$name] = $this->getService($id); + } + + return $connections; + } + + /** + * {@inheritDoc} + */ + public function getDefaultConnectionName() + { + return $this->defaultConnection; + } + + /** + * {@inheritDoc} + */ + public function getDefaultManagerName() + { + return $this->defaultManager; + } + + /** + * {@inheritDoc} + * + * @throws InvalidArgumentException + */ + public function getManager(?string $name = null) + { + if ($name === null) { + $name = $this->defaultManager; + } + + if (! isset($this->managers[$name])) { + throw new InvalidArgumentException( + sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name) + ); + } + + $service = $this->getService($this->managers[$name]); + assert($service instanceof ObjectManager); + + return $service; + } + + /** + * {@inheritDoc} + */ + public function getManagerForClass(string $class) + { + $proxyClass = new ReflectionClass($class); + if ($proxyClass->isAnonymous()) { + return null; + } + + if ($proxyClass->implementsInterface($this->proxyInterfaceName)) { + $parentClass = $proxyClass->getParentClass(); + + if ($parentClass === false) { + return null; + } + + $class = $parentClass->getName(); + } + + foreach ($this->managers as $id) { + $manager = $this->getService($id); + assert($manager instanceof ObjectManager); + + if (! $manager->getMetadataFactory()->isTransient($class)) { + return $manager; + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + public function getManagerNames() + { + return $this->managers; + } + + /** + * {@inheritDoc} + */ + public function getManagers() + { + $managers = []; + + foreach ($this->managers as $name => $id) { + $manager = $this->getService($id); + assert($manager instanceof ObjectManager); + $managers[$name] = $manager; + } + + return $managers; + } + + /** + * {@inheritDoc} + */ + public function getRepository( + string $persistentObject, + ?string $persistentManagerName = null + ) { + return $this + ->selectManager($persistentObject, $persistentManagerName) + ->getRepository($persistentObject); + } + + /** + * {@inheritDoc} + */ + public function resetManager(?string $name = null) + { + if ($name === null) { + $name = $this->defaultManager; + } + + if (! isset($this->managers[$name])) { + throw new InvalidArgumentException(sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name)); + } + + // force the creation of a new document manager + // if the current one is closed + $this->resetService($this->managers[$name]); + + return $this->getManager($name); + } + + /** @psalm-param class-string $persistentObject */ + private function selectManager( + string $persistentObject, + ?string $persistentManagerName = null + ): ObjectManager { + if ($persistentManagerName !== null) { + return $this->getManager($persistentManagerName); + } + + return $this->getManagerForClass($persistentObject) ?? $this->getManager(); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/ConnectionRegistry.php b/vendor/doctrine/persistence/src/Persistence/ConnectionRegistry.php new file mode 100644 index 0000000..59d9a74 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/ConnectionRegistry.php @@ -0,0 +1,41 @@ + An array of Connection instances. + */ + public function getConnections(); + + /** + * Gets all connection names. + * + * @return array An array of connection names. + */ + public function getConnectionNames(); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Event/LifecycleEventArgs.php b/vendor/doctrine/persistence/src/Persistence/Event/LifecycleEventArgs.php new file mode 100644 index 0000000..1654de4 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Event/LifecycleEventArgs.php @@ -0,0 +1,54 @@ +object = $object; + $this->objectManager = $objectManager; + } + + /** + * Retrieves the associated object. + * + * @return object + */ + public function getObject() + { + return $this->object; + } + + /** + * Retrieves the associated ObjectManager. + * + * @return ObjectManager + * @psalm-return TObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Event/LoadClassMetadataEventArgs.php b/vendor/doctrine/persistence/src/Persistence/Event/LoadClassMetadataEventArgs.php new file mode 100644 index 0000000..aa92d5d --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Event/LoadClassMetadataEventArgs.php @@ -0,0 +1,61 @@ + + * @template-covariant TObjectManager of ObjectManager + */ +class LoadClassMetadataEventArgs extends EventArgs +{ + /** + * @var ClassMetadata + * @psalm-var TClassMetadata + */ + private $classMetadata; + + /** + * @var ObjectManager + * @psalm-var TObjectManager + */ + private $objectManager; + + /** + * @psalm-param TClassMetadata $classMetadata + * @psalm-param TObjectManager $objectManager + */ + public function __construct(ClassMetadata $classMetadata, ObjectManager $objectManager) + { + $this->classMetadata = $classMetadata; + $this->objectManager = $objectManager; + } + + /** + * Retrieves the associated ClassMetadata. + * + * @return ClassMetadata + * @psalm-return TClassMetadata + */ + public function getClassMetadata() + { + return $this->classMetadata; + } + + /** + * Retrieves the associated ObjectManager. + * + * @return TObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Event/ManagerEventArgs.php b/vendor/doctrine/persistence/src/Persistence/Event/ManagerEventArgs.php new file mode 100644 index 0000000..5156013 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Event/ManagerEventArgs.php @@ -0,0 +1,39 @@ +objectManager = $objectManager; + } + + /** + * Retrieves the associated ObjectManager. + * + * @return ObjectManager + * @psalm-return TObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Event/OnClearEventArgs.php b/vendor/doctrine/persistence/src/Persistence/Event/OnClearEventArgs.php new file mode 100644 index 0000000..519a887 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Event/OnClearEventArgs.php @@ -0,0 +1,42 @@ +objectManager = $objectManager; + } + + /** + * Retrieves the associated ObjectManager. + * + * @return ObjectManager + * @psalm-return TObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Event/PreUpdateEventArgs.php b/vendor/doctrine/persistence/src/Persistence/Event/PreUpdateEventArgs.php new file mode 100644 index 0000000..95ecbd4 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Event/PreUpdateEventArgs.php @@ -0,0 +1,110 @@ + + */ +class PreUpdateEventArgs extends LifecycleEventArgs +{ + /** @var array> */ + private $entityChangeSet; + + /** + * @param array> $changeSet + * @psalm-param TObjectManager $objectManager + */ + public function __construct(object $entity, ObjectManager $objectManager, array &$changeSet) + { + parent::__construct($entity, $objectManager); + + $this->entityChangeSet = &$changeSet; + } + + /** + * Retrieves the entity changeset. + * + * @return array> + */ + public function getEntityChangeSet() + { + return $this->entityChangeSet; + } + + /** + * Checks if field has a changeset. + * + * @return bool + */ + public function hasChangedField(string $field) + { + return isset($this->entityChangeSet[$field]); + } + + /** + * Gets the old value of the changeset of the changed field. + * + * @return mixed + */ + public function getOldValue(string $field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][0]; + } + + /** + * Gets the new value of the changeset of the changed field. + * + * @return mixed + */ + public function getNewValue(string $field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][1]; + } + + /** + * Sets the new value of this field. + * + * @param mixed $value + * + * @return void + */ + public function setNewValue(string $field, $value) + { + $this->assertValidField($field); + + $this->entityChangeSet[$field][1] = $value; + } + + /** + * Asserts the field exists in changeset. + * + * @return void + * + * @throws InvalidArgumentException + */ + private function assertValidField(string $field) + { + if (! isset($this->entityChangeSet[$field])) { + throw new InvalidArgumentException(sprintf( + 'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.', + $field, + get_class($this->getObject()) + )); + } + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/ManagerRegistry.php b/vendor/doctrine/persistence/src/Persistence/ManagerRegistry.php new file mode 100644 index 0000000..46599a5 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/ManagerRegistry.php @@ -0,0 +1,89 @@ + An array of ObjectManager instances + */ + public function getManagers(); + + /** + * Resets a named object manager. + * + * This method is useful when an object manager has been closed + * because of a rollbacked transaction AND when you think that + * it makes sense to get a new one to replace the closed one. + * + * Be warned that you will get a brand new object manager as + * the existing one is not useable anymore. This means that any + * other object with a dependency on this object manager will + * hold an obsolete reference. You can inject the registry instead + * to avoid this problem. + * + * @param string|null $name The object manager name (null for the default one). + * + * @return ObjectManager + */ + public function resetManager(?string $name = null); + + /** + * Gets all object manager names and associated service IDs. A service ID + * is a string that allows to obtain an object manager, typically from a + * PSR-11 container. + * + * @return array An array with object manager names as keys, + * and service IDs as values. + */ + public function getManagerNames(); + + /** + * Gets the ObjectRepository for a persistent object. + * + * @param string $persistentObject The name of the persistent object. + * @param string|null $persistentManagerName The object manager name (null for the default one). + * @psalm-param class-string $persistentObject + * + * @return ObjectRepository + * @psalm-return ObjectRepository + * + * @template T of object + */ + public function getRepository( + string $persistentObject, + ?string $persistentManagerName = null + ); + + /** + * Gets the object manager associated with a given class. + * + * @param class-string $class A persistent object class name. + * + * @return ObjectManager|null + */ + public function getManagerForClass(string $class); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php b/vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php new file mode 100644 index 0000000..e8f6aca --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -0,0 +1,499 @@ + + */ +abstract class AbstractClassMetadataFactory implements ClassMetadataFactory +{ + /** + * Salt used by specific Object Manager implementation. + * + * @var string + */ + protected $cacheSalt = '__CLASSMETADATA__'; + + /** @var CacheItemPoolInterface|null */ + private $cache; + + /** + * @var array + * @psalm-var CMTemplate[] + */ + private $loadedMetadata = []; + + /** @var bool */ + protected $initialized = false; + + /** @var ReflectionService|null */ + private $reflectionService = null; + + /** @var ProxyClassNameResolver|null */ + private $proxyClassNameResolver = null; + + public function setCache(CacheItemPoolInterface $cache): void + { + $this->cache = $cache; + } + + final protected function getCache(): ?CacheItemPoolInterface + { + return $this->cache; + } + + /** + * Returns an array of all the loaded metadata currently in memory. + * + * @return ClassMetadata[] + * @psalm-return CMTemplate[] + */ + public function getLoadedMetadata() + { + return $this->loadedMetadata; + } + + /** + * {@inheritDoc} + */ + public function getAllMetadata() + { + if (! $this->initialized) { + $this->initialize(); + } + + $driver = $this->getDriver(); + $metadata = []; + foreach ($driver->getAllClassNames() as $className) { + $metadata[] = $this->getMetadataFor($className); + } + + return $metadata; + } + + public function setProxyClassNameResolver(ProxyClassNameResolver $resolver): void + { + $this->proxyClassNameResolver = $resolver; + } + + /** + * Lazy initialization of this stuff, especially the metadata driver, + * since these are not needed at all when a metadata cache is active. + * + * @return void + */ + abstract protected function initialize(); + + /** + * Returns the mapping driver implementation. + * + * @return MappingDriver + */ + abstract protected function getDriver(); + + /** + * Wakes up reflection after ClassMetadata gets unserialized from cache. + * + * @psalm-param CMTemplate $class + * + * @return void + */ + abstract protected function wakeupReflection( + ClassMetadata $class, + ReflectionService $reflService + ); + + /** + * Initializes Reflection after ClassMetadata was constructed. + * + * @psalm-param CMTemplate $class + * + * @return void + */ + abstract protected function initializeReflection( + ClassMetadata $class, + ReflectionService $reflService + ); + + /** + * Checks whether the class metadata is an entity. + * + * This method should return false for mapped superclasses or embedded classes. + * + * @psalm-param CMTemplate $class + * + * @return bool + */ + abstract protected function isEntity(ClassMetadata $class); + + /** + * Removes the prepended backslash of a class string to conform with how php outputs class names + * + * @psalm-param class-string $className + * + * @psalm-return class-string + */ + private function normalizeClassName(string $className): string + { + return ltrim($className, '\\'); + } + + /** + * {@inheritDoc} + * + * @throws ReflectionException + * @throws MappingException + */ + public function getMetadataFor(string $className) + { + $className = $this->normalizeClassName($className); + + if (isset($this->loadedMetadata[$className])) { + return $this->loadedMetadata[$className]; + } + + if (class_exists($className, false) && (new ReflectionClass($className))->isAnonymous()) { + throw MappingException::classIsAnonymous($className); + } + + if (! class_exists($className, false) && strpos($className, ':') !== false) { + throw MappingException::nonExistingClass($className); + } + + $realClassName = $this->getRealClass($className); + + if (isset($this->loadedMetadata[$realClassName])) { + // We do not have the alias name in the map, include it + return $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; + } + + try { + if ($this->cache !== null) { + $cached = $this->cache->getItem($this->getCacheKey($realClassName))->get(); + if ($cached instanceof ClassMetadata) { + /** @psalm-var CMTemplate $cached */ + $this->loadedMetadata[$realClassName] = $cached; + + $this->wakeupReflection($cached, $this->getReflectionService()); + } else { + $loadedMetadata = $this->loadMetadata($realClassName); + $classNames = array_combine( + array_map([$this, 'getCacheKey'], $loadedMetadata), + $loadedMetadata + ); + + foreach ($this->cache->getItems(array_keys($classNames)) as $item) { + if (! isset($classNames[$item->getKey()])) { + continue; + } + + $item->set($this->loadedMetadata[$classNames[$item->getKey()]]); + $this->cache->saveDeferred($item); + } + + $this->cache->commit(); + } + } else { + $this->loadMetadata($realClassName); + } + } catch (MappingException $loadingException) { + $fallbackMetadataResponse = $this->onNotFoundMetadata($realClassName); + + if ($fallbackMetadataResponse === null) { + throw $loadingException; + } + + $this->loadedMetadata[$realClassName] = $fallbackMetadataResponse; + } + + if ($className !== $realClassName) { + // We do not have the alias name in the map, include it + $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; + } + + return $this->loadedMetadata[$className]; + } + + /** + * {@inheritDoc} + */ + public function hasMetadataFor(string $className) + { + $className = $this->normalizeClassName($className); + + return isset($this->loadedMetadata[$className]); + } + + /** + * Sets the metadata descriptor for a specific class. + * + * NOTE: This is only useful in very special cases, like when generating proxy classes. + * + * @psalm-param class-string $className + * @psalm-param CMTemplate $class + * + * @return void + */ + public function setMetadataFor(string $className, ClassMetadata $class) + { + $this->loadedMetadata[$this->normalizeClassName($className)] = $class; + } + + /** + * Gets an array of parent classes for the given entity class. + * + * @psalm-param class-string $name + * + * @return string[] + * @psalm-return list + */ + protected function getParentClasses(string $name) + { + // Collect parent classes, ignoring transient (not-mapped) classes. + $parentClasses = []; + + foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) { + if ($this->getDriver()->isTransient($parentClass)) { + continue; + } + + $parentClasses[] = $parentClass; + } + + return $parentClasses; + } + + /** + * Loads the metadata of the class in question and all it's ancestors whose metadata + * is still not loaded. + * + * Important: The class $name does not necessarily exist at this point here. + * Scenarios in a code-generation setup might have access to XML/YAML + * Mapping files without the actual PHP code existing here. That is why the + * {@see \Doctrine\Persistence\Mapping\ReflectionService} interface + * should be used for reflection. + * + * @param string $name The name of the class for which the metadata should get loaded. + * @psalm-param class-string $name + * + * @return array + * @psalm-return list + */ + protected function loadMetadata(string $name) + { + if (! $this->initialized) { + $this->initialize(); + } + + $loaded = []; + + $parentClasses = $this->getParentClasses($name); + $parentClasses[] = $name; + + // Move down the hierarchy of parent classes, starting from the topmost class + $parent = null; + $rootEntityFound = false; + $visited = []; + $reflService = $this->getReflectionService(); + + foreach ($parentClasses as $className) { + if (isset($this->loadedMetadata[$className])) { + $parent = $this->loadedMetadata[$className]; + + if ($this->isEntity($parent)) { + $rootEntityFound = true; + + array_unshift($visited, $className); + } + + continue; + } + + $class = $this->newClassMetadataInstance($className); + $this->initializeReflection($class, $reflService); + + $this->doLoadMetadata($class, $parent, $rootEntityFound, $visited); + + $this->loadedMetadata[$className] = $class; + + $parent = $class; + + if ($this->isEntity($class)) { + $rootEntityFound = true; + + array_unshift($visited, $className); + } + + $this->wakeupReflection($class, $reflService); + + $loaded[] = $className; + } + + return $loaded; + } + + /** + * Provides a fallback hook for loading metadata when loading failed due to reflection/mapping exceptions + * + * Override this method to implement a fallback strategy for failed metadata loading + * + * @return ClassMetadata|null + * @psalm-return CMTemplate|null + */ + protected function onNotFoundMetadata(string $className) + { + return null; + } + + /** + * Actually loads the metadata from the underlying metadata. + * + * @param bool $rootEntityFound True when there is another entity (non-mapped superclass) class above the current class in the PHP class hierarchy. + * @param list $nonSuperclassParents All parent class names that are not marked as mapped superclasses, with the direct parent class being the first and the root entity class the last element. + * @psalm-param CMTemplate $class + * @psalm-param CMTemplate|null $parent + * + * @return void + */ + abstract protected function doLoadMetadata( + ClassMetadata $class, + ?ClassMetadata $parent, + bool $rootEntityFound, + array $nonSuperclassParents + ); + + /** + * Creates a new ClassMetadata instance for the given class name. + * + * @psalm-param class-string $className + * + * @return ClassMetadata + * @psalm-return CMTemplate + * + * @template T of object + */ + abstract protected function newClassMetadataInstance(string $className); + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + if (! $this->initialized) { + $this->initialize(); + } + + if (class_exists($className, false) && (new ReflectionClass($className))->isAnonymous()) { + return false; + } + + if (! class_exists($className, false) && strpos($className, ':') !== false) { + throw MappingException::nonExistingClass($className); + } + + /** @psalm-var class-string $className */ + return $this->getDriver()->isTransient($className); + } + + /** + * Sets the reflectionService. + * + * @return void + */ + public function setReflectionService(ReflectionService $reflectionService) + { + $this->reflectionService = $reflectionService; + } + + /** + * Gets the reflection service associated with this metadata factory. + * + * @return ReflectionService + */ + public function getReflectionService() + { + if ($this->reflectionService === null) { + $this->reflectionService = new RuntimeReflectionService(); + } + + return $this->reflectionService; + } + + protected function getCacheKey(string $realClassName): string + { + return str_replace('\\', '__', $realClassName) . $this->cacheSalt; + } + + /** + * Gets the real class name of a class name that could be a proxy. + * + * @psalm-param class-string>|class-string $class + * + * @psalm-return class-string + * + * @template T of object + */ + private function getRealClass(string $class): string + { + if ($this->proxyClassNameResolver === null) { + $this->createDefaultProxyClassNameResolver(); + } + + assert($this->proxyClassNameResolver !== null); + + return $this->proxyClassNameResolver->resolveClassName($class); + } + + private function createDefaultProxyClassNameResolver(): void + { + $this->proxyClassNameResolver = new class implements ProxyClassNameResolver { + /** + * @psalm-param class-string>|class-string $className + * + * @psalm-return class-string + * + * @template T of object + */ + public function resolveClassName(string $className): string + { + $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); + + if ($pos === false) { + /** @psalm-var class-string */ + return $className; + } + + /** @psalm-var class-string */ + return substr($className, $pos + Proxy::MARKER_LENGTH + 2); + } + }; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadata.php b/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadata.php new file mode 100644 index 0000000..f407ba3 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadata.php @@ -0,0 +1,141 @@ + + */ + public function getName(); + + /** + * Gets the mapped identifier field name. + * + * The returned structure is an array of the identifier field names. + * + * @return array + * @psalm-return list + */ + public function getIdentifier(); + + /** + * Gets the ReflectionClass instance for this mapped class. + * + * @return ReflectionClass + */ + public function getReflectionClass(); + + /** + * Checks if the given field name is a mapped identifier for this class. + * + * @return bool + */ + public function isIdentifier(string $fieldName); + + /** + * Checks if the given field is a mapped property for this class. + * + * @return bool + */ + public function hasField(string $fieldName); + + /** + * Checks if the given field is a mapped association for this class. + * + * @return bool + */ + public function hasAssociation(string $fieldName); + + /** + * Checks if the given field is a mapped single valued association for this class. + * + * @return bool + */ + public function isSingleValuedAssociation(string $fieldName); + + /** + * Checks if the given field is a mapped collection valued association for this class. + * + * @return bool + */ + public function isCollectionValuedAssociation(string $fieldName); + + /** + * A numerically indexed list of field names of this persistent class. + * + * This array includes identifier fields if present on this class. + * + * @return array + */ + public function getFieldNames(); + + /** + * Returns an array of identifier field names numerically indexed. + * + * @return array + */ + public function getIdentifierFieldNames(); + + /** + * Returns a numerically indexed list of association names of this persistent class. + * + * This array includes identifier associations if present on this class. + * + * @return array + */ + public function getAssociationNames(); + + /** + * Returns a type name of this field. + * + * This type names can be implementation specific but should at least include the php types: + * integer, string, boolean, float/double, datetime. + * + * @return string|null + */ + public function getTypeOfField(string $fieldName); + + /** + * Returns the target class name of the given association. + * + * @return string|null + * @psalm-return class-string|null + */ + public function getAssociationTargetClass(string $assocName); + + /** + * Checks if the association is the inverse side of a bidirectional association. + * + * @return bool + */ + public function isAssociationInverseSide(string $assocName); + + /** + * Returns the target field of the owning side of the association. + * + * @return string + */ + public function getAssociationMappedByTargetField(string $assocName); + + /** + * Returns the identifier of this object as an array with field name as key. + * + * Has to return an empty array if no identifier isset. + * + * @return array + */ + public function getIdentifierValues(object $object); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadataFactory.php b/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadataFactory.php new file mode 100644 index 0000000..28b8303 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/ClassMetadataFactory.php @@ -0,0 +1,61 @@ + + */ + public function getAllMetadata(); + + /** + * Gets the class metadata descriptor for a class. + * + * @param class-string $className The name of the class. + * + * @return ClassMetadata + * @psalm-return T + */ + public function getMetadataFor(string $className); + + /** + * Checks whether the factory has the metadata for a class loaded already. + * + * @param class-string $className + * + * @return bool TRUE if the metadata of the class in question is already loaded, FALSE otherwise. + */ + public function hasMetadataFor(string $className); + + /** + * Sets the metadata descriptor for a specific class. + * + * @param class-string $className + * @psalm-param T $class + * + * @return void + */ + public function setMetadataFor(string $className, ClassMetadata $class); + + /** + * Returns whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped directly or as a MappedSuperclass. + * + * @psalm-param class-string $className + * + * @return bool + */ + public function isTransient(string $className); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php new file mode 100644 index 0000000..e85ba70 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php @@ -0,0 +1,212 @@ + + */ + protected $paths = []; + + /** + * The paths excluded from path where to look for mapping files. + * + * @var array + */ + protected $excludePaths = []; + + /** + * The file extension of mapping documents. + * + * @var string + */ + protected $fileExtension = '.php'; + + /** + * Cache for getAllClassNames(). + * + * @var array|null + * @psalm-var list|null + */ + protected $classNames; + + /** + * Appends lookup paths to metadata driver. + * + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieves the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Append exclude lookup paths to metadata driver. + * + * @param string[] $paths + * + * @return void + */ + public function addExcludePaths(array $paths) + { + $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths)); + } + + /** + * Retrieve the defined metadata lookup exclude paths. + * + * @return array + */ + public function getExcludePaths() + { + return $this->excludePaths; + } + + /** + * Gets the file extension used to look for mapping files under. + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @return void + */ + public function setFileExtension(string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + * + * Returns whether the class with the specified name is transient. Only non-transient + * classes, that is entities and mapped superclasses, should have their metadata loaded. + * + * @psalm-param class-string $className + * + * @return bool + */ + abstract public function isTransient(string $className); + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return string[] The names of all mapped classes known to this driver. + * @psalm-return list + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if ($this->paths === []) { + throw MappingException::pathRequiredForDriver(static::class); + } + + $classes = []; + $includedFiles = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RegexIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::LEAVES_ONLY + ), + '/^.+' . preg_quote($this->fileExtension) . '$/i', + RecursiveRegexIterator::GET_MATCH + ); + + foreach ($iterator as $file) { + $sourceFile = $file[0]; + + if (preg_match('(^phar:)i', $sourceFile) === 0) { + $sourceFile = realpath($sourceFile); + } + + foreach ($this->excludePaths as $excludePath) { + $realExcludePath = realpath($excludePath); + assert($realExcludePath !== false); + $exclude = str_replace('\\', '/', $realExcludePath); + $current = str_replace('\\', '/', $sourceFile); + + if (strpos($current, $exclude) !== false) { + continue 2; + } + } + + require_once $sourceFile; + + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new ReflectionClass($className); + + $sourceFile = $rc->getFileName(); + + if (! in_array($sourceFile, $includedFiles, true) || $this->isTransient($className)) { + continue; + } + + $classes[] = $className; + } + + $this->classNames = $classes; + + return $classes; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php new file mode 100644 index 0000000..9b00e74 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/DefaultFileLocator.php @@ -0,0 +1,175 @@ + + */ + protected $paths = []; + + /** + * The file extension of mapping documents. + * + * @var string|null + */ + protected $fileExtension; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array $paths One or multiple paths where mapping documents + * can be found. + * @param string|null $fileExtension The file extension of mapping documents, + * usually prefixed with a dot. + */ + public function __construct($paths, ?string $fileExtension = null) + { + $this->addPaths((array) $paths); + $this->fileExtension = $fileExtension; + } + + /** + * Appends lookup paths to metadata driver. + * + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieves the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Gets the file extension used to look for mapping files under. + * + * @return string|null + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @param string|null $fileExtension The file extension to set. + * + * @return void + */ + public function setFileExtension(?string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile(string $className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ($this->paths as $path) { + if (is_file($path . DIRECTORY_SEPARATOR . $fileName)) { + return $path . DIRECTORY_SEPARATOR . $fileName; + } + } + + throw MappingException::mappingFileNotFound($className, $fileName); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames(string $globalBasename) + { + if ($this->paths === []) { + return []; + } + + $classes = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName === $file->getBasename() || $fileName === $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + + assert(is_string($fileName)); + /** @psalm-var class-string */ + $class = str_replace('.', '\\', $fileName); + $classes[] = $class; + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function fileExists(string $className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ($this->paths as $path) { + if (is_file($path . DIRECTORY_SEPARATOR . $fileName)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php new file mode 100644 index 0000000..c116233 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileDriver.php @@ -0,0 +1,213 @@ +|null + */ + protected $classCache; + + /** @var string */ + protected $globalBasename = ''; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array|FileLocator $locator A FileLocator or one/multiple paths + * where mapping documents can be found. + */ + public function __construct($locator, ?string $fileExtension = null) + { + if ($locator instanceof FileLocator) { + $this->locator = $locator; + } else { + $this->locator = new DefaultFileLocator((array) $locator, $fileExtension); + } + } + + /** + * Sets the global basename. + * + * @return void + */ + public function setGlobalBasename(string $file) + { + $this->globalBasename = $file; + } + + /** + * Retrieves the global basename. + * + * @return string|null + */ + public function getGlobalBasename() + { + return $this->globalBasename; + } + + /** + * Gets the element of schema meta data for the class from the mapping file. + * This will lazily load the mapping file if it is not loaded yet. + * + * @psalm-param class-string $className + * + * @return T The element of schema meta data. + * + * @throws MappingException + */ + public function getElement(string $className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return $this->classCache[$className]; + } + + $result = $this->loadMappingFile($this->locator->findMappingFile($className)); + + if (! isset($result[$className])) { + throw MappingException::invalidMappingFile( + $className, + str_replace('\\', '.', $className) . $this->locator->getFileExtension() + ); + } + + $this->classCache[$className] = $result[$className]; + + return $result[$className]; + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return false; + } + + return ! $this->locator->fileExists($className); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + if ($this->classCache === null) { + $this->initialize(); + } + + if ($this->classCache === []) { + return $this->locator->getAllClassNames($this->globalBasename); + } + + /** @psalm-var array> $classCache */ + $classCache = $this->classCache; + + /** @var list $keys */ + $keys = array_keys($classCache); + + return array_values(array_unique(array_merge( + $keys, + $this->locator->getAllClassNames($this->globalBasename) + ))); + } + + /** + * Loads a mapping file with the given name and returns a map + * from class/entity names to their corresponding file driver elements. + * + * @param string $file The mapping file to load. + * + * @return mixed[] + * @psalm-return array + */ + abstract protected function loadMappingFile(string $file); + + /** + * Initializes the class cache from all the global files. + * + * Using this feature adds a substantial performance hit to file drivers as + * more metadata has to be loaded into memory than might actually be + * necessary. This may not be relevant to scenarios where caching of + * metadata is in place, however hits very hard in scenarios where no + * caching is used. + * + * @return void + */ + protected function initialize() + { + $this->classCache = []; + if ($this->globalBasename === '') { + return; + } + + foreach ($this->locator->getPaths() as $path) { + $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension(); + if (! is_file($file)) { + continue; + } + + $this->classCache = array_merge( + $this->classCache, + $this->loadMappingFile($file) + ); + } + } + + /** + * Retrieves the locator used to discover mapping files by className. + * + * @return FileLocator + */ + public function getLocator() + { + return $this->locator; + } + + /** + * Sets the locator used to discover mapping files by className. + * + * @return void + */ + public function setLocator(FileLocator $locator) + { + $this->locator = $locator; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php new file mode 100644 index 0000000..e57d539 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/FileLocator.php @@ -0,0 +1,52 @@ + + * @psalm-return list + */ + public function getAllClassNames(string $globalBasename); + + /** + * Checks if a file can be found for this class name. + * + * @return bool + */ + public function fileExists(string $className); + + /** + * Gets all the paths that this file locator looks for mapping files. + * + * @return array + */ + public function getPaths(); + + /** + * Gets the file extension that mapping files are suffixed with. + * + * @return string|null + */ + public function getFileExtension(); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php new file mode 100644 index 0000000..9b6f0c8 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriver.php @@ -0,0 +1,43 @@ + $className + * @psalm-param ClassMetadata $metadata + * + * @return void + * + * @template T of object + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata); + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return array The names of all mapped classes known to this driver. + * @psalm-return list + */ + public function getAllClassNames(); + + /** + * Returns whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped as an Entity or a MappedSuperclass. + * + * @psalm-param class-string $className + * + * @return bool + */ + public function isTransient(string $className); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php new file mode 100644 index 0000000..8563dd2 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/MappingDriverChain.php @@ -0,0 +1,142 @@ + */ + private $drivers = []; + + /** + * Gets the default driver. + * + * @return MappingDriver|null + */ + public function getDefaultDriver() + { + return $this->defaultDriver; + } + + /** + * Set the default driver. + * + * @return void + */ + public function setDefaultDriver(MappingDriver $driver) + { + $this->defaultDriver = $driver; + } + + /** + * Adds a nested driver. + * + * @return void + */ + public function addDriver(MappingDriver $nestedDriver, string $namespace) + { + $this->drivers[$namespace] = $nestedDriver; + } + + /** + * Gets the array of nested drivers. + * + * @return array $drivers + */ + public function getDrivers() + { + return $this->drivers; + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + foreach ($this->drivers as $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + $driver->loadMetadataForClass($className, $metadata); + + return; + } + } + + if ($this->defaultDriver !== null) { + $this->defaultDriver->loadMetadataForClass($className, $metadata); + + return; + } + + throw MappingException::classNotFoundInNamespaces($className, array_keys($this->drivers)); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + $classNames = []; + $driverClasses = []; + + foreach ($this->drivers as $namespace => $driver) { + $oid = spl_object_hash($driver); + + if (! isset($driverClasses[$oid])) { + $driverClasses[$oid] = $driver->getAllClassNames(); + } + + foreach ($driverClasses[$oid] as $className) { + if (strpos($className, $namespace) !== 0) { + continue; + } + + $classNames[$className] = true; + } + } + + if ($this->defaultDriver !== null) { + foreach ($this->defaultDriver->getAllClassNames() as $className) { + $classNames[$className] = true; + } + } + + return array_keys($classNames); + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + foreach ($this->drivers as $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + return $driver->isTransient($className); + } + } + + if ($this->defaultDriver !== null) { + return $this->defaultDriver->isTransient($className); + } + + return true; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php new file mode 100644 index 0000000..1c1ab9c --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/PHPDriver.php @@ -0,0 +1,49 @@ +> + */ +class PHPDriver extends FileDriver +{ + /** + * @var ClassMetadata + * @psalm-var ClassMetadata + */ + protected $metadata; + + /** @param string|array|FileLocator $locator */ + public function __construct($locator) + { + parent::__construct($locator, '.php'); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + $this->metadata = $metadata; + + $this->loadMappingFile($this->locator->findMappingFile($className)); + } + + /** + * {@inheritDoc} + */ + protected function loadMappingFile(string $file) + { + $metadata = $this->metadata; + include $file; + + return [$metadata->getName() => $metadata]; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php new file mode 100644 index 0000000..bbcff75 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/StaticPHPDriver.php @@ -0,0 +1,132 @@ + + */ + private $paths = []; + + /** + * Map of all class names. + * + * @var array + * @psalm-var list + */ + private $classNames; + + /** @param array|string $paths */ + public function __construct($paths) + { + $this->addPaths((array) $paths); + } + + /** + * @param array $paths + * + * @return void + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass(string $className, ClassMetadata $metadata) + { + $className::loadMetadata($metadata); + } + + /** + * {@inheritDoc} + * + * @todo Same code exists in ColocatedMappingDriver, should we re-use it + * somehow or not worry about it? + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if ($this->paths === []) { + throw MappingException::pathRequiredForDriver(static::class); + } + + $classes = []; + $includedFiles = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + if ($file->getBasename('.php') === $file->getBasename()) { + continue; + } + + $sourceFile = realpath($file->getPathName()); + require_once $sourceFile; + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new ReflectionClass($className); + + $sourceFile = $rc->getFileName(); + + if (! in_array($sourceFile, $includedFiles, true) || $this->isTransient($className)) { + continue; + } + + $classes[] = $className; + } + + $this->classNames = $classes; + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function isTransient(string $className) + { + return ! method_exists($className, 'loadMetadata'); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php new file mode 100644 index 0000000..428d5fb --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/Driver/SymfonyFileLocator.php @@ -0,0 +1,265 @@ + + */ + protected $paths = []; + + /** + * A map of mapping directory path to namespace prefix used to expand class shortnames. + * + * @var array + */ + protected $prefixes = []; + + /** + * File extension that is searched for. + * + * @var string|null + */ + protected $fileExtension; + + /** + * Represents PHP namespace delimiters when looking for files + * + * @var string + */ + private $nsSeparator; + + /** + * @param array $prefixes + * @param string $nsSeparator String which would be used when converting FQCN + * to filename and vice versa. Should not be empty + */ + public function __construct( + array $prefixes, + string $fileExtension = '', + string $nsSeparator = '.' + ) { + $this->addNamespacePrefixes($prefixes); + $this->fileExtension = $fileExtension; + + if ($nsSeparator === '') { + throw new InvalidArgumentException('Namespace separator should not be empty'); + } + + $this->nsSeparator = $nsSeparator; + } + + /** + * Adds Namespace Prefixes. + * + * @param array $prefixes + * + * @return void + */ + public function addNamespacePrefixes(array $prefixes) + { + $this->prefixes = array_merge($this->prefixes, $prefixes); + $this->paths = array_merge($this->paths, array_keys($prefixes)); + } + + /** + * Gets Namespace Prefixes. + * + * @return string[] + */ + public function getNamespacePrefixes() + { + return $this->prefixes; + } + + /** + * {@inheritDoc} + */ + public function getPaths() + { + return $this->paths; + } + + /** + * {@inheritDoc} + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Sets the file extension used to look for mapping files under. + * + * @param string $fileExtension The file extension to set. + * + * @return void + */ + public function setFileExtension(string $fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function fileExists(string $className) + { + $defaultFileName = str_replace('\\', $this->nsSeparator, $className) . $this->fileExtension; + foreach ($this->paths as $path) { + if (! isset($this->prefixes[$path])) { + // global namespace class + if (is_file($path . DIRECTORY_SEPARATOR . $defaultFileName)) { + return true; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (strpos($className, $prefix . '\\') !== 0) { + continue; + } + + $filename = $path . '/' . strtr(substr($className, strlen($prefix) + 1), '\\', $this->nsSeparator) . $this->fileExtension; + + if (is_file($filename)) { + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames(?string $globalBasename = null) + { + if ($this->paths === []) { + return []; + } + + $classes = []; + + foreach ($this->paths as $path) { + if (! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName === $file->getBasename() || $fileName === $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + if (isset($this->prefixes[$path])) { + // Calculate namespace suffix for given prefix as a relative path from basepath to file path + $nsSuffix = strtr( + substr($this->realpath($file->getPath()), strlen($this->realpath($path))), + $this->nsSeparator, + '\\' + ); + + /** @psalm-var class-string */ + $class = $this->prefixes[$path] . str_replace(DIRECTORY_SEPARATOR, '\\', $nsSuffix) . '\\' . str_replace($this->nsSeparator, '\\', $fileName); + } else { + /** @psalm-var class-string */ + $class = str_replace($this->nsSeparator, '\\', $fileName); + } + + $classes[] = $class; + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile(string $className) + { + $defaultFileName = str_replace('\\', $this->nsSeparator, $className) . $this->fileExtension; + foreach ($this->paths as $path) { + if (! isset($this->prefixes[$path])) { + if (is_file($path . DIRECTORY_SEPARATOR . $defaultFileName)) { + return $path . DIRECTORY_SEPARATOR . $defaultFileName; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (strpos($className, $prefix . '\\') !== 0) { + continue; + } + + $filename = $path . '/' . strtr(substr($className, strlen($prefix) + 1), '\\', $this->nsSeparator) . $this->fileExtension; + if (is_file($filename)) { + return $filename; + } + } + + $pos = strrpos($className, '\\'); + assert(is_int($pos)); + + throw MappingException::mappingFileNotFound( + $className, + substr($className, $pos + 1) . $this->fileExtension + ); + } + + private function realpath(string $path): string + { + $realpath = realpath($path); + + if ($realpath === false) { + throw new RuntimeException(sprintf('Could not get realpath for %s', $path)); + } + + return $realpath; + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/MappingException.php b/vendor/doctrine/persistence/src/Persistence/Mapping/MappingException.php new file mode 100644 index 0000000..f0bc4eb --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/MappingException.php @@ -0,0 +1,88 @@ + $namespaces + * + * @return self + */ + public static function classNotFoundInNamespaces( + string $className, + array $namespaces + ) { + return new self(sprintf( + "The class '%s' was not found in the chain configured namespaces %s", + $className, + implode(', ', $namespaces) + )); + } + + /** @param class-string $driverClassName */ + public static function pathRequiredForDriver(string $driverClassName): self + { + return new self(sprintf( + 'Specifying the paths to your entities is required when using %s to retrieve all class names.', + $driverClassName + )); + } + + /** @return self */ + public static function fileMappingDriversRequireConfiguredDirectoryPath( + ?string $path = null + ) { + if ($path !== null) { + $path = '[' . $path . ']'; + } + + return new self(sprintf( + 'File mapping drivers must have a valid directory path, ' . + 'however the given path %s seems to be incorrect!', + (string) $path + )); + } + + /** @return self */ + public static function mappingFileNotFound(string $entityName, string $fileName) + { + return new self(sprintf( + "No mapping file found named '%s' for class '%s'.", + $fileName, + $entityName + )); + } + + /** @return self */ + public static function invalidMappingFile(string $entityName, string $fileName) + { + return new self(sprintf( + "Invalid mapping file '%s' for class '%s'.", + $fileName, + $entityName + )); + } + + /** @return self */ + public static function nonExistingClass(string $className) + { + return new self(sprintf("Class '%s' does not exist", $className)); + } + + /** @param class-string $className */ + public static function classIsAnonymous(string $className): self + { + return new self(sprintf('Class "%s" is anonymous', $className)); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/ProxyClassNameResolver.php b/vendor/doctrine/persistence/src/Persistence/Mapping/ProxyClassNameResolver.php new file mode 100644 index 0000000..2801d90 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/ProxyClassNameResolver.php @@ -0,0 +1,19 @@ +>|class-string $className + * + * @psalm-return class-string + * + * @template T of object + */ + public function resolveClassName(string $className): string; +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/ReflectionService.php b/vendor/doctrine/persistence/src/Persistence/Mapping/ReflectionService.php new file mode 100644 index 0000000..9484e1f --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/ReflectionService.php @@ -0,0 +1,75 @@ + $class + * + * @return ReflectionClass|null + * @psalm-return ReflectionClass|null + * + * @template T of object + */ + public function getClass(string $class); + + /** + * Returns an accessible property (setAccessible(true)) or null. + * + * @psalm-param class-string $class + * + * @return ReflectionProperty|null + */ + public function getAccessibleProperty(string $class, string $property); + + /** + * Checks if the class have a public method with the given name. + * + * @psalm-param class-string $class + * + * @return bool + */ + public function hasPublicMethod(string $class, string $method); +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/RuntimeReflectionService.php b/vendor/doctrine/persistence/src/Persistence/Mapping/RuntimeReflectionService.php new file mode 100644 index 0000000..399e057 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/RuntimeReflectionService.php @@ -0,0 +1,111 @@ +supportsTypedPropertiesWorkaround = version_compare(phpversion(), '7.4.0') >= 0; + } + + /** + * {@inheritDoc} + */ + public function getParentClasses(string $class) + { + if (! class_exists($class)) { + throw MappingException::nonExistingClass($class); + } + + $parents = class_parents($class); + + assert($parents !== false); + + return $parents; + } + + /** + * {@inheritDoc} + */ + public function getClassShortName(string $class) + { + $reflectionClass = new ReflectionClass($class); + + return $reflectionClass->getShortName(); + } + + /** + * {@inheritDoc} + */ + public function getClassNamespace(string $class) + { + $reflectionClass = new ReflectionClass($class); + + return $reflectionClass->getNamespaceName(); + } + + /** + * @psalm-param class-string $class + * + * @return ReflectionClass + * @psalm-return ReflectionClass + * + * @template T of object + */ + public function getClass(string $class) + { + return new ReflectionClass($class); + } + + /** + * {@inheritDoc} + */ + public function getAccessibleProperty(string $class, string $property) + { + $reflectionProperty = new RuntimeReflectionProperty($class, $property); + + if ($this->supportsTypedPropertiesWorkaround && ! array_key_exists($property, $this->getClass($class)->getDefaultProperties())) { + $reflectionProperty = new TypedNoDefaultReflectionProperty($class, $property); + } + + $reflectionProperty->setAccessible(true); + + return $reflectionProperty; + } + + /** + * {@inheritDoc} + */ + public function hasPublicMethod(string $class, string $method) + { + try { + $reflectionMethod = new ReflectionMethod($class, $method); + } catch (ReflectionException $e) { + return false; + } + + return $reflectionMethod->isPublic(); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Mapping/StaticReflectionService.php b/vendor/doctrine/persistence/src/Persistence/Mapping/StaticReflectionService.php new file mode 100644 index 0000000..c9f2147 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Mapping/StaticReflectionService.php @@ -0,0 +1,78 @@ +find($id). + * + * @param string $className The class name of the object to find. + * @param mixed $id The identity of the object to find. + * @psalm-param class-string $className + * + * @return object|null The found object. + * @psalm-return T|null + * + * @template T of object + */ + public function find(string $className, $id); + + /** + * Tells the ObjectManager to make an instance managed and persistent. + * + * The object will be entered into the database as a result of the flush operation. + * + * NOTE: The persist operation always considers objects that are not yet known to + * this ObjectManager as NEW. Do not pass detached objects to the persist operation. + * + * @param object $object The instance to make managed and persistent. + * + * @return void + */ + public function persist(object $object); + + /** + * Removes an object instance. + * + * A removed object will be removed from the database as a result of the flush operation. + * + * @param object $object The object instance to remove. + * + * @return void + */ + public function remove(object $object); + + /** + * Clears the ObjectManager. All objects that are currently managed + * by this ObjectManager become detached. + * + * @return void + */ + public function clear(); + + /** + * Detaches an object from the ObjectManager, causing a managed object to + * become detached. Unflushed changes made to the object if any + * (including removal of the object), will not be synchronized to the database. + * Objects which previously referenced the detached object will continue to + * reference it. + * + * @param object $object The object to detach. + * + * @return void + */ + public function detach(object $object); + + /** + * Refreshes the persistent state of an object from the database, + * overriding any local changes that have not yet been persisted. + * + * @param object $object The object to refresh. + * + * @return void + */ + public function refresh(object $object); + + /** + * Flushes all changes to objects that have been queued up to now to the database. + * This effectively synchronizes the in-memory state of managed objects with the + * database. + * + * @return void + */ + public function flush(); + + /** + * Gets the repository for a class. + * + * @psalm-param class-string $className + * + * @psalm-return ObjectRepository + * + * @template T of object + */ + public function getRepository(string $className); + + /** + * Returns the ClassMetadata descriptor for a class. + * + * The class name must be the fully-qualified class name without a leading backslash + * (as it is returned by get_class($obj)). + * + * @psalm-param class-string $className + * + * @psalm-return ClassMetadata + * + * @template T of object + */ + public function getClassMetadata(string $className); + + /** + * Gets the metadata factory used to gather the metadata of classes. + * + * @psalm-return ClassMetadataFactory> + */ + public function getMetadataFactory(); + + /** + * Helper method to initialize a lazy loading proxy or persistent collection. + * + * This method is a no-op for other objects. + * + * @return void + */ + public function initializeObject(object $obj); + + /** + * Checks if the object is part of the current UnitOfWork and therefore managed. + * + * @return bool + */ + public function contains(object $object); +} diff --git a/vendor/doctrine/persistence/src/Persistence/ObjectManagerDecorator.php b/vendor/doctrine/persistence/src/Persistence/ObjectManagerDecorator.php new file mode 100644 index 0000000..8c038b8 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/ObjectManagerDecorator.php @@ -0,0 +1,92 @@ +wrapped->find($className, $id); + } + + public function persist(object $object) + { + $this->wrapped->persist($object); + } + + public function remove(object $object) + { + $this->wrapped->remove($object); + } + + public function clear(): void + { + $this->wrapped->clear(); + } + + public function detach(object $object) + { + $this->wrapped->detach($object); + } + + public function refresh(object $object) + { + $this->wrapped->refresh($object); + } + + public function flush() + { + $this->wrapped->flush(); + } + + /** + * {@inheritDoc} + */ + public function getRepository(string $className) + { + return $this->wrapped->getRepository($className); + } + + /** + * {@inheritDoc} + */ + public function getClassMetadata(string $className) + { + return $this->wrapped->getClassMetadata($className); + } + + /** @psalm-return ClassMetadataFactory> */ + public function getMetadataFactory() + { + return $this->wrapped->getMetadataFactory(); + } + + public function initializeObject(object $obj) + { + $this->wrapped->initializeObject($obj); + } + + /** + * {@inheritDoc} + */ + public function contains(object $object) + { + return $this->wrapped->contains($object); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/ObjectRepository.php b/vendor/doctrine/persistence/src/Persistence/ObjectRepository.php new file mode 100644 index 0000000..a714731 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/ObjectRepository.php @@ -0,0 +1,73 @@ + The objects. + * @psalm-return T[] + */ + public function findAll(); + + /** + * Finds objects by a set of criteria. + * + * Optionally sorting and limiting details can be passed. An implementation may throw + * an UnexpectedValueException if certain values of the sorting or limiting details are + * not supported. + * + * @param array $criteria + * @param array|null $orderBy + * @psalm-param array|null $orderBy + * + * @return array The objects. + * @psalm-return T[] + * + * @throws UnexpectedValueException + */ + public function findBy( + array $criteria, + ?array $orderBy = null, + ?int $limit = null, + ?int $offset = null + ); + + /** + * Finds a single object by a set of criteria. + * + * @param array $criteria The criteria. + * + * @return object|null The object. + * @psalm-return T|null + */ + public function findOneBy(array $criteria); + + /** + * Returns the class name of the object managed by the repository. + * + * @psalm-return class-string + */ + public function getClassName(); +} diff --git a/vendor/doctrine/persistence/src/Persistence/PropertyChangedListener.php b/vendor/doctrine/persistence/src/Persistence/PropertyChangedListener.php new file mode 100644 index 0000000..6b50707 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/PropertyChangedListener.php @@ -0,0 +1,24 @@ + */ + private $enumType; + + /** @param class-string $enumType */ + public function __construct(ReflectionProperty $originalReflectionProperty, string $enumType) + { + $this->originalReflectionProperty = $originalReflectionProperty; + $this->enumType = $enumType; + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function getDeclaringClass(): ReflectionClass + { + return $this->originalReflectionProperty->getDeclaringClass(); + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function getName(): string + { + return $this->originalReflectionProperty->getName(); + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function getType(): ?ReflectionType + { + return $this->originalReflectionProperty->getType(); + } + + /** + * {@inheritDoc} + */ + public function getAttributes(?string $name = null, int $flags = 0): array + { + return $this->originalReflectionProperty->getAttributes($name, $flags); + } + + /** + * {@inheritDoc} + * + * Converts enum instance to its value. + * + * @param object|null $object + * + * @return int|string|int[]|string[]|null + */ + #[ReturnTypeWillChange] + public function getValue($object = null) + { + if ($object === null) { + return null; + } + + $enum = $this->originalReflectionProperty->getValue($object); + + if ($enum === null) { + return null; + } + + return $this->fromEnum($enum); + } + + /** + * Converts enum value to enum instance. + * + * @param object $object + * @param mixed $value + */ + public function setValue($object, $value = null): void + { + if ($value !== null) { + $value = $this->toEnum($value); + } + + $this->originalReflectionProperty->setValue($object, $value); + } + + /** + * @param BackedEnum|BackedEnum[] $enum + * + * @return ($enum is BackedEnum ? (string|int) : (string[]|int[])) + */ + private function fromEnum($enum) + { + if (is_array($enum)) { + return array_map(static function (BackedEnum $enum) { + return $enum->value; + }, $enum); + } + + return $enum->value; + } + + /** + * @param int|string|int[]|string[]|BackedEnum|BackedEnum[] $value + * + * @return ($value is int|string|BackedEnum ? BackedEnum : BackedEnum[]) + */ + private function toEnum($value) + { + if ($value instanceof BackedEnum) { + return $value; + } + + if (is_array($value)) { + $v = reset($value); + if ($v instanceof BackedEnum) { + return $value; + } + + return array_map([$this->enumType, 'from'], $value); + } + + return $this->enumType::from($value); + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function getModifiers(): int + { + return $this->originalReflectionProperty->getModifiers(); + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function getDocComment(): string|false + { + return $this->originalReflectionProperty->getDocComment(); + } + + /** + * {@inheritDoc} + * + * @psalm-external-mutation-free + */ + public function isPrivate(): bool + { + return $this->originalReflectionProperty->isPrivate(); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimePublicReflectionProperty.php b/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimePublicReflectionProperty.php new file mode 100644 index 0000000..e2367ec --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimePublicReflectionProperty.php @@ -0,0 +1,61 @@ +getName()] ?? null : parent::getValue(); + } + + /** + * {@inheritDoc} + * + * Avoids triggering lazy loading via `__set` if the provided object + * is a {@see \Doctrine\Common\Proxy\Proxy}. + * + * @link https://bugs.php.net/bug.php?id=63463 + * + * @param object|null $object + * @param mixed $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function setValue($object, $value = null) + { + if (! ($object instanceof Proxy && ! $object->__isInitialized())) { + parent::setValue($object, $value); + + return; + } + + $originalInitializer = $object->__getInitializer(); + $object->__setInitializer(null); + + parent::setValue($object, $value); + + $object->__setInitializer($originalInitializer); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimeReflectionProperty.php b/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimeReflectionProperty.php new file mode 100644 index 0000000..5f52056 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Reflection/RuntimeReflectionProperty.php @@ -0,0 +1,87 @@ +key = $this->isPrivate() ? "\0" . ltrim($class, '\\') . "\0" . $name : ($this->isProtected() ? "\0*\0" . $name : $name); + } + + /** + * {@inheritDoc} + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function getValue($object = null) + { + if ($object === null) { + return parent::getValue($object); + } + + return ((array) $object)[$this->key] ?? null; + } + + /** + * {@inheritDoc} + * + * @param object|null $object + * @param mixed $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function setValue($object, $value = null) + { + if (! ($object instanceof Proxy && ! $object->__isInitialized())) { + parent::setValue($object, $value); + + return; + } + + if ($object instanceof CommonProxy) { + $originalInitializer = $object->__getInitializer(); + $object->__setInitializer(null); + + parent::setValue($object, $value); + + $object->__setInitializer($originalInitializer); + + return; + } + + if (! method_exists($object, '__setInitialized')) { + return; + } + + $object->__setInitialized(true); + + parent::setValue($object, $value); + + $object->__setInitialized(false); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultReflectionProperty.php b/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultReflectionProperty.php new file mode 100644 index 0000000..5e70620 --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultReflectionProperty.php @@ -0,0 +1,13 @@ +isInitialized($object) ? parent::getValue($object) : null; + } + + /** + * {@inheritDoc} + * + * Works around the problem with setting typed no default properties to + * NULL which is not supported, instead unset() to uninitialize. + * + * @link https://github.com/doctrine/orm/issues/7999 + * + * @param object|null $object + * + * @return void + */ + #[ReturnTypeWillChange] + public function setValue($object, $value = null) + { + if ($value === null && $this->hasType() && ! $this->getType()->allowsNull()) { + $propertyName = $this->getName(); + + $unsetter = function () use ($propertyName): void { + unset($this->$propertyName); + }; + $unsetter = $unsetter->bindTo($object, $this->getDeclaringClass()->getName()); + + assert($unsetter instanceof Closure); + + $unsetter(); + + return; + } + + parent::setValue($object, $value); + } +} diff --git a/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultRuntimePublicReflectionProperty.php b/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultRuntimePublicReflectionProperty.php new file mode 100644 index 0000000..181172f --- /dev/null +++ b/vendor/doctrine/persistence/src/Persistence/Reflection/TypedNoDefaultRuntimePublicReflectionProperty.php @@ -0,0 +1,15 @@ +