diff options
author | Devian <devianleong@gmail.com> | 2021-04-22 17:03:46 +0800 |
---|---|---|
committer | Devian <devianleong@gmail.com> | 2021-04-22 17:03:46 +0800 |
commit | 745cf2431a71d0e6c5f08f8605839279b2f7496e (patch) | |
tree | 11e4c7a19ac9f9efc1bb253b29b1fa488c34238e /vendor/doctrine/common/lib |
Initiate commit
Diffstat (limited to 'vendor/doctrine/common/lib')
14 files changed, 2484 insertions, 0 deletions
diff --git a/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php b/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php new file mode 100644 index 0000000..2a53bad --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php @@ -0,0 +1,289 @@ +<?php + +namespace Doctrine\Common; + +use function class_exists; +use function interface_exists; +use function is_array; +use function is_file; +use function reset; +use function spl_autoload_functions; +use function spl_autoload_register; +use function spl_autoload_unregister; +use function str_replace; +use function stream_resolve_include_path; +use function strpos; +use function trait_exists; +use function trigger_error; + +use const DIRECTORY_SEPARATOR; +use const E_USER_DEPRECATED; + +@trigger_error(ClassLoader::class . ' is deprecated.', E_USER_DEPRECATED); + +/** + * A <tt>ClassLoader</tt> is an autoloader for class files that can be + * installed on the SPL autoload stack. It is a class loader that either loads only classes + * of a specific namespace or all namespaces and it is suitable for working together + * with other autoloaders in the SPL autoload stack. + * + * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader + * relies on the PHP <code>include_path</code>. + * + * @deprecated The ClassLoader is deprecated and will be removed in version 4.0 of doctrine/common. + */ +class ClassLoader +{ + /** + * PHP file extension. + * + * @var string + */ + protected $fileExtension = '.php'; + + /** + * Current namespace. + * + * @var string|null + */ + protected $namespace; + + /** + * Current include path. + * + * @var string|null + */ + protected $includePath; + + /** + * PHP namespace separator. + * + * @var string + */ + protected $namespaceSeparator = '\\'; + + /** + * Creates a new <tt>ClassLoader</tt> that loads classes of the + * specified namespace from the specified include path. + * + * If no include path is given, the ClassLoader relies on the PHP include_path. + * If neither a namespace nor an include path is given, the ClassLoader will + * be responsible for loading all classes, thereby relying on the PHP include_path. + * + * @param string|null $ns The namespace of the classes to load. + * @param string|null $includePath The base include path to use. + */ + public function __construct($ns = null, $includePath = null) + { + $this->namespace = $ns; + $this->includePath = $includePath; + } + + /** + * Sets the namespace separator used by classes in the namespace of this ClassLoader. + * + * @param string $sep The separator to use. + * + * @return void + */ + public function setNamespaceSeparator($sep) + { + $this->namespaceSeparator = $sep; + } + + /** + * Gets the namespace separator used by classes in the namespace of this ClassLoader. + * + * @return string + */ + public function getNamespaceSeparator() + { + return $this->namespaceSeparator; + } + + /** + * Sets the base include path for all class files in the namespace of this ClassLoader. + * + * @param string|null $includePath + * + * @return void + */ + public function setIncludePath($includePath) + { + $this->includePath = $includePath; + } + + /** + * Gets the base include path for all class files in the namespace of this ClassLoader. + * + * @return string|null + */ + public function getIncludePath() + { + return $this->includePath; + } + + /** + * Sets the file extension of class files in the namespace of this ClassLoader. + * + * @param string $fileExtension + * + * @return void + */ + public function setFileExtension($fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * Gets the file extension of class files in the namespace of this ClassLoader. + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Registers this ClassLoader on the SPL autoload stack. + * + * @return void + */ + public function register() + { + spl_autoload_register([$this, 'loadClass']); + } + + /** + * Removes this ClassLoader from the SPL autoload stack. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister([$this, 'loadClass']); + } + + /** + * Loads the given class or interface. + * + * @param string $className The name of the class to load. + * + * @return bool TRUE if the class has been successfully loaded, FALSE otherwise. + * + * @psalm-param class-string $className + */ + public function loadClass($className) + { + if (self::typeExists($className)) { + return true; + } + + if (! $this->canLoadClass($className)) { + return false; + } + + require($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') + . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) + . $this->fileExtension; + + return self::typeExists($className); + } + + /** + * Asks this ClassLoader whether it can potentially load the class (file) with + * the given name. + * + * @param string $className The fully-qualified name of the class. + * + * @return bool TRUE if this ClassLoader can load the class, FALSE otherwise. + * + * @psalm-param class-string $className + */ + public function canLoadClass($className) + { + if ($this->namespace !== null && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) { + return false; + } + + $file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; + + if ($this->includePath !== null) { + return is_file($this->includePath . DIRECTORY_SEPARATOR . $file); + } + + return stream_resolve_include_path($file) !== false; + } + + /** + * Checks whether a class with a given name exists. A class "exists" if it is either + * already defined in the current request or if there is an autoloader on the SPL + * autoload stack that is a) responsible for the class in question and b) is able to + * load a class file in which the class definition resides. + * + * If the class is not already defined, each autoloader in the SPL autoload stack + * is asked whether it is able to tell if the class exists. If the autoloader is + * a <tt>ClassLoader</tt>, {@link canLoadClass} is used, otherwise the autoload + * function of the autoloader is invoked and expected to return a value that + * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports + * that the class exists, TRUE is returned. + * + * Note that, depending on what kinds of autoloaders are installed on the SPL + * autoload stack, the class (file) might already be loaded as a result of checking + * for its existence. This is not the case with a <tt>ClassLoader</tt>, who separates + * these responsibilities. + * + * @param string $className The fully-qualified name of the class. + * + * @return bool TRUE if the class exists as per the definition given above, FALSE otherwise. + * + * @psalm-param class-string $className + */ + public static function classExists($className) + { + return self::typeExists($className, true); + } + + /** + * Gets the <tt>ClassLoader</tt> from the SPL autoload stack that is responsible + * for (and is able to load) the class with the given name. + * + * @param string $className The name of the class. + * + * @return ClassLoader|null The <tt>ClassLoader</tt> for the class or NULL if no such <tt>ClassLoader</tt> exists. + * + * @psalm-param class-string $className + */ + public static function getClassLoader($className) + { + foreach (spl_autoload_functions() as $loader) { + if (! is_array($loader)) { + continue; + } + + $classLoader = reset($loader); + + if ($classLoader instanceof ClassLoader && $classLoader->canLoadClass($className)) { + return $classLoader; + } + } + + return null; + } + + /** + * Checks whether a given type exists + * + * @param string $type + * @param bool $autoload + * + * @return bool + */ + private static function typeExists($type, $autoload = false) + { + return class_exists($type, $autoload) + || interface_exists($type, $autoload) + || trait_exists($type, $autoload); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php b/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php new file mode 100644 index 0000000..a2aba0e --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php @@ -0,0 +1,14 @@ +<?php + +namespace Doctrine\Common; + +use Exception; + +/** + * Base exception class for package Doctrine\Common. + * + * @deprecated The doctrine/common package is deprecated, please use specific packages and their exceptions instead. + */ +class CommonException extends Exception +{ +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php b/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php new file mode 100644 index 0000000..f9ac4be --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php @@ -0,0 +1,26 @@ +<?php + +namespace Doctrine\Common; + +/** + * Comparable interface that allows to compare two value objects to each other for similarity. + * + * @link www.doctrine-project.org + */ +interface Comparable +{ + /** + * Compares the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantical equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other + * + * @return int + */ + public function compareTo($other); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php new file mode 100644 index 0000000..a7af281 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php @@ -0,0 +1,230 @@ +<?php + +namespace Doctrine\Common\Proxy; + +use Doctrine\Common\Proxy\Exception\InvalidArgumentException; +use Doctrine\Common\Proxy\Exception\OutOfBoundsException; +use Doctrine\Common\Util\ClassUtils; +use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadataFactory; + +use function class_exists; +use function file_exists; +use function in_array; +use function interface_exists; + +/** + * Abstract factory for proxy objects. + */ +abstract class AbstractProxyFactory +{ + /** + * Never autogenerate a proxy and rely that it was generated by some + * process before deployment. + */ + public const AUTOGENERATE_NEVER = 0; + + /** + * Always generates a new proxy in every request. + * + * This is only sane during development. + */ + public const AUTOGENERATE_ALWAYS = 1; + + /** + * Autogenerate the proxy class when the proxy file does not exist. + * + * This strategy causes a file exists call whenever any proxy is used the + * first time in a request. + */ + public const AUTOGENERATE_FILE_NOT_EXISTS = 2; + + /** + * Generate the proxy classes using eval(). + * + * This strategy is only sane for development, and even then it gives me + * the creeps a little. + */ + public const AUTOGENERATE_EVAL = 3; + + private const AUTOGENERATE_MODES = [ + self::AUTOGENERATE_NEVER, + self::AUTOGENERATE_ALWAYS, + self::AUTOGENERATE_FILE_NOT_EXISTS, + self::AUTOGENERATE_EVAL, + ]; + + /** @var ClassMetadataFactory */ + private $metadataFactory; + + /** @var ProxyGenerator the proxy generator responsible for creating the proxy classes/files. */ + private $proxyGenerator; + + /** @var int Whether to automatically (re)generate proxy classes. */ + private $autoGenerate; + + /** @var ProxyDefinition[] */ + private $definitions = []; + + /** + * @param bool|int $autoGenerate + * + * @throws InvalidArgumentException When auto generate mode is not valid. + */ + public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate) + { + $this->proxyGenerator = $proxyGenerator; + $this->metadataFactory = $metadataFactory; + $this->autoGenerate = (int) $autoGenerate; + + if (! in_array($this->autoGenerate, self::AUTOGENERATE_MODES, true)) { + throw InvalidArgumentException::invalidAutoGenerateMode($autoGenerate); + } + } + + /** + * Gets a reference proxy instance for the entity of the given type and identified by + * the given identifier. + * + * @param string $className + * @param array<mixed> $identifier + * + * @return Proxy + * + * @throws OutOfBoundsException + */ + public function getProxy($className, array $identifier) + { + $definition = $this->definitions[$className] ?? $this->getProxyDefinition($className); + $fqcn = $definition->proxyClassName; + $proxy = new $fqcn($definition->initializer, $definition->cloner); + + foreach ($definition->identifierFields as $idField) { + if (! isset($identifier[$idField])) { + throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField); + } + + $definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]); + } + + return $proxy; + } + + /** + * Generates proxy classes for all given classes. + * + * @param ClassMetadata[] $classes The classes (ClassMetadata instances) + * for which to generate proxies. + * @param string $proxyDir The target directory of the proxy classes. If not specified, the + * directory configured on the Configuration of the EntityManager used + * by this factory is used. + * + * @return int Number of generated proxies. + */ + public function generateProxyClasses(array $classes, $proxyDir = null) + { + $generated = 0; + + foreach ($classes as $class) { + if ($this->skipClass($class)) { + continue; + } + + $proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir); + + $this->proxyGenerator->generateProxyClass($class, $proxyFileName); + + $generated += 1; + } + + return $generated; + } + + /** + * Reset initialization/cloning logic for an un-initialized proxy + * + * @return Proxy + * + * @throws InvalidArgumentException + */ + public function resetUninitializedProxy(Proxy $proxy) + { + if ($proxy->__isInitialized()) { + throw InvalidArgumentException::unitializedProxyExpected($proxy); + } + + $className = ClassUtils::getClass($proxy); + $definition = $this->definitions[$className] ?? $this->getProxyDefinition($className); + + $proxy->__setInitializer($definition->initializer); + $proxy->__setCloner($definition->cloner); + + return $proxy; + } + + /** + * Get a proxy definition for the given class name. + * + * @param string $className + * + * @return ProxyDefinition + * + * @psalm-param class-string $className + */ + private function getProxyDefinition($className) + { + $classMetadata = $this->metadataFactory->getMetadataFor($className); + $className = $classMetadata->getName(); // aliases and case sensitivity + + $this->definitions[$className] = $this->createProxyDefinition($className); + $proxyClassName = $this->definitions[$className]->proxyClassName; + + if (! class_exists($proxyClassName, false)) { + $fileName = $this->proxyGenerator->getProxyFileName($className); + + switch ($this->autoGenerate) { + case self::AUTOGENERATE_NEVER: + require $fileName; + break; + + case self::AUTOGENERATE_FILE_NOT_EXISTS: + if (! file_exists($fileName)) { + $this->proxyGenerator->generateProxyClass($classMetadata, $fileName); + } + + require $fileName; + break; + + case self::AUTOGENERATE_ALWAYS: + $this->proxyGenerator->generateProxyClass($classMetadata, $fileName); + require $fileName; + break; + + case self::AUTOGENERATE_EVAL: + $this->proxyGenerator->generateProxyClass($classMetadata, false); + break; + } + } + + return $this->definitions[$className]; + } + + /** + * Determine if this class should be skipped during proxy generation. + * + * @return bool + */ + abstract protected function skipClass(ClassMetadata $metadata); + + /** + * @param string $className + * + * @return ProxyDefinition + * + * @psalm-param class-string $className + */ + abstract protected function createProxyDefinition($className); +} + +interface_exists(ClassMetadata::class); +interface_exists(ClassMetadataFactory::class); diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php new file mode 100644 index 0000000..58d221a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php @@ -0,0 +1,100 @@ +<?php + +namespace Doctrine\Common\Proxy; + +use Closure; +use Doctrine\Common\Proxy\Exception\InvalidArgumentException; + +use function call_user_func; +use function file_exists; +use function is_callable; +use function ltrim; +use function spl_autoload_register; +use function str_replace; +use function strlen; +use function strpos; +use function substr; + +use const DIRECTORY_SEPARATOR; + +/** + * Special Autoloader for Proxy classes, which are not PSR-0 compliant. + * + * @internal + */ +class Autoloader +{ + /** + * Resolves proxy class name to a filename based on the following pattern. + * + * 1. Remove Proxy namespace from class name. + * 2. Remove namespace separators from remaining class name. + * 3. Return PHP filename from proxy-dir with the result from 2. + * + * @param string $proxyDir + * @param string $proxyNamespace + * @param string $className + * + * @return string + * + * @throws InvalidArgumentException + * + * @psalm-param class-string $className + */ + public static function resolveFile($proxyDir, $proxyNamespace, $className) + { + if (strpos($className, $proxyNamespace) !== 0) { + throw InvalidArgumentException::notProxyClass($className, $proxyNamespace); + } + + // remove proxy namespace from class name + $classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace)); + + // remove namespace separators from remaining class name + $fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace); + + return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php'; + } + + /** + * Registers and returns autoloader callback for the given proxy dir and namespace. + * + * @param string $proxyDir + * @param string $proxyNamespace + * @param callable|null $notFoundCallback Invoked when the proxy file is not found. + * + * @return Closure + * + * @throws InvalidArgumentException + */ + public static function register($proxyDir, $proxyNamespace, $notFoundCallback = null) + { + $proxyNamespace = ltrim($proxyNamespace, '\\'); + + if ($notFoundCallback !== null && ! is_callable($notFoundCallback)) { + throw InvalidArgumentException::invalidClassNotFoundCallback($notFoundCallback); + } + + $autoloader = static function ($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) { + if ($proxyNamespace === '') { + return; + } + + if (strpos($className, $proxyNamespace) !== 0) { + return; + } + + $file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); + + if ($notFoundCallback && ! file_exists($file)) { + call_user_func($notFoundCallback, $proxyDir, $proxyNamespace, $className); + } + + require $file; + }; + + spl_autoload_register($autoloader); + + return $autoloader; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..db92809 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php @@ -0,0 +1,113 @@ +<?php + +namespace Doctrine\Common\Proxy\Exception; + +use Doctrine\Persistence\Proxy; +use InvalidArgumentException as BaseInvalidArgumentException; + +use function get_class; +use function gettype; +use function interface_exists; +use function is_object; +use function sprintf; + +/** + * Proxy Invalid Argument Exception. + * + * @link www.doctrine-project.org + */ +class InvalidArgumentException extends BaseInvalidArgumentException implements ProxyException +{ + /** + * @return self + */ + public static function proxyDirectoryRequired() + { + return new self('You must configure a proxy directory. See docs for details'); + } + + /** + * @param string $className + * @param string $proxyNamespace + * + * @return self + * + * @psalm-param class-string $className + */ + public static function notProxyClass($className, $proxyNamespace) + { + return new self(sprintf('The class "%s" is not part of the proxy namespace "%s"', $className, $proxyNamespace)); + } + + /** + * @param string $name + * + * @return self + */ + public static function invalidPlaceholder($name) + { + return new self(sprintf('Provided placeholder for "%s" must be either a string or a valid callable', $name)); + } + + /** + * @return self + */ + public static function proxyNamespaceRequired() + { + return new self('You must configure a proxy namespace'); + } + + /** + * @return self + */ + public static function unitializedProxyExpected(Proxy $proxy) + { + return new self(sprintf('Provided proxy of type "%s" must not be initialized.', get_class($proxy))); + } + + /** + * @param mixed $callback + * + * @return self + */ + public static function invalidClassNotFoundCallback($callback) + { + $type = is_object($callback) ? get_class($callback) : gettype($callback); + + return new self(sprintf('Invalid \$notFoundCallback given: must be a callable, "%s" given', $type)); + } + + /** + * @param string $className + * + * @return self + * + * @psalm-param class-string $className + */ + public static function classMustNotBeAbstract($className) + { + return new self(sprintf('Unable to create a proxy for an abstract class "%s".', $className)); + } + + /** + * @param string $className + * + * @return self + * + * @psalm-param class-string $className + */ + public static function classMustNotBeFinal($className) + { + return new self(sprintf('Unable to create a proxy for a final class "%s".', $className)); + } + + /** + * @param mixed $value + */ + public static function invalidAutoGenerateMode($value): self + { + return new self(sprintf('Invalid auto generate mode "%s" given.', $value)); + } +} + +interface_exists(Proxy::class); diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php new file mode 100644 index 0000000..b9fde45 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php @@ -0,0 +1,28 @@ +<?php + +namespace Doctrine\Common\Proxy\Exception; + +use OutOfBoundsException as BaseOutOfBoundsException; + +use function sprintf; + +/** + * Proxy Invalid Argument Exception. + * + * @link www.doctrine-project.org + */ +class OutOfBoundsException extends BaseOutOfBoundsException implements ProxyException +{ + /** + * @param string $className + * @param string $idField + * + * @return self + * + * @psalm-param class-string $className + */ + public static function missingPrimaryKeyValue($className, $idField) + { + return new self(sprintf('Missing value for primary key %s on %s', $idField, $className)); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php new file mode 100644 index 0000000..f827fbd --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php @@ -0,0 +1,12 @@ +<?php + +namespace Doctrine\Common\Proxy\Exception; + +/** + * Base exception interface for proxy exceptions. + * + * @link www.doctrine-project.org + */ +interface ProxyException +{ +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php new file mode 100644 index 0000000..9f85a1a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php @@ -0,0 +1,74 @@ +<?php + +namespace Doctrine\Common\Proxy\Exception; + +use Throwable; +use UnexpectedValueException as BaseUnexpectedValueException; + +use function sprintf; + +/** + * Proxy Unexpected Value Exception. + * + * @link www.doctrine-project.org + */ +class UnexpectedValueException extends BaseUnexpectedValueException implements ProxyException +{ + /** + * @param string $proxyDirectory + * + * @return self + */ + public static function proxyDirectoryNotWritable($proxyDirectory) + { + return new self(sprintf('Your proxy directory "%s" must be writable', $proxyDirectory)); + } + + /** + * @param string $className + * @param string $methodName + * @param string $parameterName + * + * @return self + * + * @psalm-param class-string $className + */ + public static function invalidParameterTypeHint( + $className, + $methodName, + $parameterName, + ?Throwable $previous = null + ) { + return new self( + sprintf( + 'The type hint of parameter "%s" in method "%s" in class "%s" is invalid.', + $parameterName, + $methodName, + $className + ), + 0, + $previous + ); + } + + /** + * @param string $className + * @param string $methodName + * + * @return self + * + * @psalm-param class-string $className + */ + public static function invalidReturnTypeHint($className, $methodName, ?Throwable $previous = null) + { + return new self( + sprintf( + 'The return type of method "%s" in class "%s" is invalid.', + $methodName, + $className + ), + 0, + $previous + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php new file mode 100644 index 0000000..93f144a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php @@ -0,0 +1,65 @@ +<?php + +namespace Doctrine\Common\Proxy; + +use Closure; +use Doctrine\Persistence\Proxy as BaseProxy; + +/** + * Interface for proxy classes. + */ +interface Proxy extends BaseProxy +{ + /** + * Marks the proxy as initialized or not. + * + * @param bool $initialized + * + * @return void + */ + public function __setInitialized($initialized); + + /** + * Sets the initializer callback to be used when initializing the proxy. That + * initializer should accept 3 parameters: $proxy, $method and $params. Those + * are respectively the proxy object that is being initialized, the method name + * that triggered initialization and the parameters passed to that method. + * + * @return void + */ + public function __setInitializer(?Closure $initializer = null); + + /** + * Retrieves the initializer callback used to initialize the proxy. + * + * @see __setInitializer + * + * @return Closure|null + */ + public function __getInitializer(); + + /** + * Sets the callback to be used when cloning the proxy. That initializer should accept + * a single parameter, which is the cloned proxy instance itself. + * + * @return void + */ + public function __setCloner(?Closure $cloner = null); + + /** + * Retrieves the callback to be used when cloning the proxy. + * + * @see __setCloner + * + * @return Closure|null + */ + public function __getCloner(); + + /** + * Retrieves the list of lazy loaded properties for a given proxy + * + * @return array<string, mixed> Keys are the property names, and values are the default values + * for those properties. + */ + public function __getLazyProperties(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php new file mode 100644 index 0000000..a7f3957 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php @@ -0,0 +1,42 @@ +<?php + +namespace Doctrine\Common\Proxy; + +use ReflectionProperty; + +/** + * Definition structure how to create a proxy. + */ +class ProxyDefinition +{ + /** @var string */ + public $proxyClassName; + + /** @var array<string> */ + public $identifierFields; + + /** @var ReflectionProperty[] */ + public $reflectionFields; + + /** @var callable */ + public $initializer; + + /** @var callable */ + public $cloner; + + /** + * @param string $proxyClassName + * @param array<string> $identifierFields + * @param array<string, ReflectionProperty> $reflectionFields + * @param callable $initializer + * @param callable $cloner + */ + public function __construct($proxyClassName, array $identifierFields, array $reflectionFields, $initializer, $cloner) + { + $this->proxyClassName = $proxyClassName; + $this->identifierFields = $identifierFields; + $this->reflectionFields = $reflectionFields; + $this->initializer = $initializer; + $this->cloner = $cloner; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php new file mode 100644 index 0000000..5504078 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php @@ -0,0 +1,1194 @@ +<?php + +namespace Doctrine\Common\Proxy; + +use Doctrine\Common\Proxy\Exception\InvalidArgumentException; +use Doctrine\Common\Proxy\Exception\UnexpectedValueException; +use Doctrine\Common\Util\ClassUtils; +use Doctrine\Persistence\Mapping\ClassMetadata; +use ReflectionMethod; +use ReflectionNamedType; +use ReflectionParameter; +use ReflectionProperty; +use ReflectionType; +use ReflectionUnionType; + +use function array_combine; +use function array_diff; +use function array_key_exists; +use function array_map; +use function array_slice; +use function assert; +use function call_user_func; +use function chmod; +use function class_exists; +use function dirname; +use function explode; +use function file; +use function file_put_contents; +use function implode; +use function in_array; +use function interface_exists; +use function is_callable; +use function is_dir; +use function is_string; +use function is_writable; +use function lcfirst; +use function ltrim; +use function method_exists; +use function mkdir; +use function preg_match; +use function preg_match_all; +use function rename; +use function rtrim; +use function sprintf; +use function str_replace; +use function strrev; +use function strtolower; +use function strtr; +use function substr; +use function trim; +use function uniqid; +use function var_export; + +use const DIRECTORY_SEPARATOR; + +/** + * This factory is used to generate proxy classes. + * It builds proxies from given parameters, a template and class metadata. + */ +class ProxyGenerator +{ + /** + * Used to match very simple id methods that don't need + * to be decorated since the identifier is known. + */ + public const PATTERN_MATCH_ID_METHOD = '((public\s+)?(function\s+%s\s*\(\)\s*)\s*(?::\s*\??\s*\\\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*\s*)?{\s*return\s*\$this->%s;\s*})i'; + + /** + * The namespace that contains all proxy classes. + * + * @var string + */ + private $proxyNamespace; + + /** + * The directory that contains all proxy classes. + * + * @var string + */ + private $proxyDirectory; + + /** + * Map of callables used to fill in placeholders set in the template. + * + * @var string[]|callable[] + */ + protected $placeholders = [ + 'baseProxyInterface' => Proxy::class, + 'additionalProperties' => '', + ]; + + /** + * Template used as a blueprint to generate proxies. + * + * @var string + */ + protected $proxyClassTemplate = '<?php + +namespace <namespace>; + +/** + * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE\'S PROXY GENERATOR + */ +class <proxyShortClassName> extends \<className> implements \<baseProxyInterface> +{ + /** + * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with + * three parameters, being respectively the proxy object to be initialized, the method that triggered the + * initialization process and an array of ordered parameters that were passed to that method. + * + * @see \Doctrine\Common\Proxy\Proxy::__setInitializer + */ + public $__initializer__; + + /** + * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object + * + * @see \Doctrine\Common\Proxy\Proxy::__setCloner + */ + public $__cloner__; + + /** + * @var boolean flag indicating if this object was already initialized + * + * @see \Doctrine\Persistence\Proxy::__isInitialized + */ + public $__isInitialized__ = false; + + /** + * @var array<string, null> properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = <lazyPropertiesNames>; + + /** + * @var array<string, mixed> default values of properties to be lazy loaded, with keys being the property names + * + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties + */ + public static $lazyPropertiesDefaults = <lazyPropertiesDefaults>; + +<additionalProperties> + +<constructorImpl> + +<magicGet> + +<magicSet> + +<magicIsset> + +<sleepImpl> + +<wakeupImpl> + +<cloneImpl> + + /** + * Forces initialization of the proxy + */ + public function __load() + { + $this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', []); + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __isInitialized() + { + return $this->__isInitialized__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitialized($initialized) + { + $this->__isInitialized__ = $initialized; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitializer(\Closure $initializer = null) + { + $this->__initializer__ = $initializer; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __getInitializer() + { + return $this->__initializer__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setCloner(\Closure $cloner = null) + { + $this->__cloner__ = $cloner; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific cloning logic + */ + public function __getCloner() + { + return $this->__cloner__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + * @deprecated no longer in use - generated code now relies on internal components rather than generated public API + * @static + */ + public function __getLazyProperties() + { + return self::$lazyPropertiesDefaults; + } + + <methods> +} +'; + + /** + * Initializes a new instance of the <tt>ProxyFactory</tt> class that is + * connected to the given <tt>EntityManager</tt>. + * + * @param string $proxyDirectory The directory to use for the proxy classes. It must exist. + * @param string $proxyNamespace The namespace to use for the proxy classes. + * + * @throws InvalidArgumentException + */ + public function __construct($proxyDirectory, $proxyNamespace) + { + if (! $proxyDirectory) { + throw InvalidArgumentException::proxyDirectoryRequired(); + } + + if (! $proxyNamespace) { + throw InvalidArgumentException::proxyNamespaceRequired(); + } + + $this->proxyDirectory = $proxyDirectory; + $this->proxyNamespace = $proxyNamespace; + } + + /** + * Sets a placeholder to be replaced in the template. + * + * @param string $name + * @param string|callable $placeholder + * + * @throws InvalidArgumentException + */ + public function setPlaceholder($name, $placeholder) + { + if (! is_string($placeholder) && ! is_callable($placeholder)) { + throw InvalidArgumentException::invalidPlaceholder($name); + } + + $this->placeholders[$name] = $placeholder; + } + + /** + * Sets the base template used to create proxy classes. + * + * @param string $proxyClassTemplate + */ + public function setProxyClassTemplate($proxyClassTemplate) + { + $this->proxyClassTemplate = (string) $proxyClassTemplate; + } + + /** + * Generates a proxy class file. + * + * @param ClassMetadata $class Metadata for the original class. + * @param string|bool $fileName Filename (full path) for the generated class. If none is given, eval() is used. + * + * @throws InvalidArgumentException + * @throws UnexpectedValueException + */ + public function generateProxyClass(ClassMetadata $class, $fileName = false) + { + $this->verifyClassCanBeProxied($class); + + preg_match_all('(<([a-zA-Z]+)>)', $this->proxyClassTemplate, $placeholderMatches); + + $placeholderMatches = array_combine($placeholderMatches[0], $placeholderMatches[1]); + $placeholders = []; + + foreach ($placeholderMatches as $placeholder => $name) { + $placeholders[$placeholder] = $this->placeholders[$name] ?? [$this, 'generate' . $name]; + } + + foreach ($placeholders as & $placeholder) { + if (! is_callable($placeholder)) { + continue; + } + + $placeholder = call_user_func($placeholder, $class); + } + + $proxyCode = strtr($this->proxyClassTemplate, $placeholders); + + if (! $fileName) { + $proxyClassName = $this->generateNamespace($class) . '\\' . $this->generateProxyShortClassName($class); + + if (! class_exists($proxyClassName)) { + eval(substr($proxyCode, 5)); + } + + return; + } + + $parentDirectory = dirname($fileName); + + if (! is_dir($parentDirectory) && (@mkdir($parentDirectory, 0775, true) === false)) { + throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory); + } + + if (! is_writable($parentDirectory)) { + throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory); + } + + $tmpFileName = $fileName . '.' . uniqid('', true); + + file_put_contents($tmpFileName, $proxyCode); + @chmod($tmpFileName, 0664); + rename($tmpFileName, $fileName); + } + + /** + * @throws InvalidArgumentException + */ + private function verifyClassCanBeProxied(ClassMetadata $class) + { + if ($class->getReflectionClass()->isFinal()) { + throw InvalidArgumentException::classMustNotBeFinal($class->getName()); + } + + if ($class->getReflectionClass()->isAbstract()) { + throw InvalidArgumentException::classMustNotBeAbstract($class->getName()); + } + } + + /** + * Generates the proxy short class name to be used in the template. + * + * @return string + */ + private function generateProxyShortClassName(ClassMetadata $class) + { + $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace); + $parts = explode('\\', strrev($proxyClassName), 2); + + return strrev($parts[0]); + } + + /** + * Generates the proxy namespace. + * + * @return string + */ + private function generateNamespace(ClassMetadata $class) + { + $proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace); + $parts = explode('\\', strrev($proxyClassName), 2); + + return strrev($parts[1]); + } + + /** + * Generates the original class name. + * + * @return string + */ + private function generateClassName(ClassMetadata $class) + { + return ltrim($class->getName(), '\\'); + } + + /** + * Generates the array representation of lazy loaded public properties and their default values. + * + * @return string + */ + private function generateLazyPropertiesNames(ClassMetadata $class) + { + $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $values = []; + + foreach ($lazyPublicProperties as $name) { + $values[$name] = null; + } + + return var_export($values, true); + } + + /** + * Generates the array representation of lazy loaded public properties names. + * + * @return string + */ + private function generateLazyPropertiesDefaults(ClassMetadata $class) + { + return var_export($this->getLazyLoadedPublicProperties($class), true); + } + + /** + * Generates the constructor code (un-setting public lazy loaded properties, setting identifier field values). + * + * @return string + */ + private function generateConstructorImpl(ClassMetadata $class) + { + $constructorImpl = <<<'EOT' + public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) + { + +EOT; + + $toUnset = array_map(static function (string $name): string { + return '$this->' . $name; + }, $this->getLazyLoadedPublicPropertiesNames($class)); + + return $constructorImpl . ($toUnset === [] ? '' : ' unset(' . implode(', ', $toUnset) . ");\n") + . <<<'EOT' + + $this->__initializer__ = $initializer; + $this->__cloner__ = $cloner; + } +EOT; + } + + /** + * Generates the magic getter invoked when lazy loaded public properties are requested. + * + * @return string + */ + private function generateMagicGet(ClassMetadata $class) + { + $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $reflectionClass = $class->getReflectionClass(); + $hasParentGet = false; + $returnReference = ''; + $inheritDoc = ''; + $name = '$name'; + $parametersString = '$name'; + $returnTypeHint = null; + + if ($reflectionClass->hasMethod('__get')) { + $hasParentGet = true; + $inheritDoc = '{@inheritDoc}'; + $methodReflection = $reflectionClass->getMethod('__get'); + + if ($methodReflection->returnsReference()) { + $returnReference = '& '; + } + + $methodParameters = $methodReflection->getParameters(); + $name = '$' . $methodParameters[0]->getName(); + + $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']); + $returnTypeHint = $this->getMethodReturnType($methodReflection); + } + + if (empty($lazyPublicProperties) && ! $hasParentGet) { + return ''; + } + + $magicGet = <<<EOT + /** + * $inheritDoc + * @param string \$name + */ + public function {$returnReference}__get($parametersString)$returnTypeHint + { + +EOT; + + if (! empty($lazyPublicProperties)) { + $magicGet .= <<<'EOT' + if (\array_key_exists($name, self::$lazyPropertiesNames)) { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]); +EOT; + + if ($returnTypeHint === ': void') { + $magicGet .= "\n return;"; + } else { + $magicGet .= "\n return \$this->\$name;"; + } + + $magicGet .= <<<'EOT' + + } + + +EOT; + } + + if ($hasParentGet) { + $magicGet .= <<<'EOT' + $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]); +EOT; + + if ($returnTypeHint === ': void') { + $magicGet .= <<<'EOT' + + parent::__get($name); + return; +EOT; + } else { + $magicGet .= <<<'EOT' + + return parent::__get($name); +EOT; + } + } else { + $magicGet .= sprintf(<<<EOT + trigger_error(sprintf('Undefined property: %%s::$%%s', __CLASS__, %s), E_USER_NOTICE); + +EOT + , $name); + } + + return $magicGet . "\n }"; + } + + /** + * Generates the magic setter (currently unused). + * + * @return string + */ + private function generateMagicSet(ClassMetadata $class) + { + $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $reflectionClass = $class->getReflectionClass(); + $hasParentSet = false; + $inheritDoc = ''; + $parametersString = '$name, $value'; + $returnTypeHint = null; + + if ($reflectionClass->hasMethod('__set')) { + $hasParentSet = true; + $inheritDoc = '{@inheritDoc}'; + $methodReflection = $reflectionClass->getMethod('__set'); + + $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name', 'value']); + $returnTypeHint = $this->getMethodReturnType($methodReflection); + } + + if (empty($lazyPublicProperties) && ! $hasParentSet) { + return ''; + } + + $magicSet = <<<EOT + /** + * $inheritDoc + * @param string \$name + * @param mixed \$value + */ + public function __set($parametersString)$returnTypeHint + { + +EOT; + + if (! empty($lazyPublicProperties)) { + $magicSet .= <<<'EOT' + if (\array_key_exists($name, self::$lazyPropertiesNames)) { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]); + + $this->$name = $value; + + return; + } + + +EOT; + } + + if ($hasParentSet) { + $magicSet .= <<<'EOT' + $this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]); +EOT; + + if ($returnTypeHint === ': void') { + $magicSet .= <<<'EOT' + + parent::__set($name, $value); + return; +EOT; + } else { + $magicSet .= <<<'EOT' + + return parent::__set($name, $value); +EOT; + } + } else { + $magicSet .= ' $this->$name = $value;'; + } + + return $magicSet . "\n }"; + } + + /** + * Generates the magic issetter invoked when lazy loaded public properties are checked against isset(). + * + * @return string + */ + private function generateMagicIsset(ClassMetadata $class) + { + $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $hasParentIsset = $class->getReflectionClass()->hasMethod('__isset'); + $parametersString = '$name'; + $returnTypeHint = null; + + if ($hasParentIsset) { + $methodReflection = $class->getReflectionClass()->getMethod('__isset'); + $parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']); + $returnTypeHint = $this->getMethodReturnType($methodReflection); + } + + if (empty($lazyPublicProperties) && ! $hasParentIsset) { + return ''; + } + + $inheritDoc = $hasParentIsset ? '{@inheritDoc}' : ''; + $magicIsset = <<<EOT + /** + * $inheritDoc + * @param string \$name + * @return boolean + */ + public function __isset($parametersString)$returnTypeHint + { + +EOT; + + if (! empty($lazyPublicProperties)) { + $magicIsset .= <<<'EOT' + if (\array_key_exists($name, self::$lazyPropertiesNames)) { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]); + + return isset($this->$name); + } + + +EOT; + } + + if ($hasParentIsset) { + $magicIsset .= <<<'EOT' + $this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]); + + return parent::__isset($name); +EOT; + } else { + $magicIsset .= ' return false;'; + } + + return $magicIsset . "\n }"; + } + + /** + * Generates implementation for the `__sleep` method of proxies. + * + * @return string + */ + private function generateSleepImpl(ClassMetadata $class) + { + $reflectionClass = $class->getReflectionClass(); + + $hasParentSleep = $reflectionClass->hasMethod('__sleep'); + $inheritDoc = $hasParentSleep ? '{@inheritDoc}' : ''; + $returnTypeHint = $hasParentSleep ? $this->getMethodReturnType($reflectionClass->getMethod('__sleep')) : ''; + $sleepImpl = <<<EOT + /** + * $inheritDoc + * @return array + */ + public function __sleep()$returnTypeHint + { + +EOT; + + if ($hasParentSleep) { + return $sleepImpl . <<<'EOT' + $properties = array_merge(['__isInitialized__'], parent::__sleep()); + + if ($this->__isInitialized__) { + $properties = array_diff($properties, array_keys(self::$lazyPropertiesNames)); + } + + return $properties; + } +EOT; + } + + $allProperties = ['__isInitialized__']; + + foreach ($class->getReflectionClass()->getProperties() as $prop) { + assert($prop instanceof ReflectionProperty); + if ($prop->isStatic()) { + continue; + } + + $allProperties[] = $prop->isPrivate() + ? "\0" . $prop->getDeclaringClass()->getName() . "\0" . $prop->getName() + : $prop->getName(); + } + + $lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $protectedProperties = array_diff($allProperties, $lazyPublicProperties); + + foreach ($allProperties as &$property) { + $property = var_export($property, true); + } + + foreach ($protectedProperties as &$property) { + $property = var_export($property, true); + } + + $allProperties = implode(', ', $allProperties); + $protectedProperties = implode(', ', $protectedProperties); + + return $sleepImpl . <<<EOT + if (\$this->__isInitialized__) { + return [$allProperties]; + } + + return [$protectedProperties]; + } +EOT; + } + + /** + * Generates implementation for the `__wakeup` method of proxies. + * + * @return string + */ + private function generateWakeupImpl(ClassMetadata $class) + { + $reflectionClass = $class->getReflectionClass(); + + $hasParentWakeup = $reflectionClass->hasMethod('__wakeup'); + + $unsetPublicProperties = []; + foreach ($this->getLazyLoadedPublicPropertiesNames($class) as $lazyPublicProperty) { + $unsetPublicProperties[] = '$this->' . $lazyPublicProperty; + } + + $shortName = $this->generateProxyShortClassName($class); + $inheritDoc = $hasParentWakeup ? '{@inheritDoc}' : ''; + $returnTypeHint = $hasParentWakeup ? $this->getMethodReturnType($reflectionClass->getMethod('__wakeup')) : ''; + $wakeupImpl = <<<EOT + /** + * $inheritDoc + */ + public function __wakeup()$returnTypeHint + { + if ( ! \$this->__isInitialized__) { + \$this->__initializer__ = function ($shortName \$proxy) { + \$proxy->__setInitializer(null); + \$proxy->__setCloner(null); + + \$existingProperties = get_object_vars(\$proxy); + + foreach (\$proxy::\$lazyPropertiesDefaults as \$property => \$defaultValue) { + if ( ! array_key_exists(\$property, \$existingProperties)) { + \$proxy->\$property = \$defaultValue; + } + } + }; + +EOT; + + if (! empty($unsetPublicProperties)) { + $wakeupImpl .= "\n unset(" . implode(', ', $unsetPublicProperties) . ');'; + } + + $wakeupImpl .= "\n }"; + + if ($hasParentWakeup) { + $wakeupImpl .= "\n parent::__wakeup();"; + } + + $wakeupImpl .= "\n }"; + + return $wakeupImpl; + } + + /** + * Generates implementation for the `__clone` method of proxies. + * + * @return string + */ + private function generateCloneImpl(ClassMetadata $class) + { + $hasParentClone = $class->getReflectionClass()->hasMethod('__clone'); + $inheritDoc = $hasParentClone ? '{@inheritDoc}' : ''; + $callParentClone = $hasParentClone ? "\n parent::__clone();\n" : ''; + + return <<<EOT + /** + * $inheritDoc + */ + public function __clone() + { + \$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', []); +$callParentClone } +EOT; + } + + /** + * Generates decorated methods by picking those available in the parent class. + * + * @return string + */ + private function generateMethods(ClassMetadata $class) + { + $methods = ''; + $methodNames = []; + $reflectionMethods = $class->getReflectionClass()->getMethods(ReflectionMethod::IS_PUBLIC); + $skippedMethods = [ + '__sleep' => true, + '__clone' => true, + '__wakeup' => true, + '__get' => true, + '__set' => true, + '__isset' => true, + ]; + + foreach ($reflectionMethods as $method) { + $name = $method->getName(); + + if ( + $method->isConstructor() || + isset($skippedMethods[strtolower($name)]) || + isset($methodNames[$name]) || + $method->isFinal() || + $method->isStatic() || + ( ! $method->isPublic()) + ) { + continue; + } + + $methodNames[$name] = true; + $methods .= "\n /**\n" + . " * {@inheritDoc}\n" + . " */\n" + . ' public function '; + + if ($method->returnsReference()) { + $methods .= '&'; + } + + $methods .= $name . '(' . $this->buildParametersString($method->getParameters()) . ')'; + $methods .= $this->getMethodReturnType($method); + $methods .= "\n" . ' {' . "\n"; + + if ($this->isShortIdentifierGetter($method, $class)) { + $identifier = lcfirst(substr($name, 3)); + $fieldType = $class->getTypeOfField($identifier); + $cast = in_array($fieldType, ['integer', 'smallint']) ? '(int) ' : ''; + + $methods .= ' if ($this->__isInitialized__ === false) {' . "\n"; + $methods .= ' '; + $methods .= $this->shouldProxiedMethodReturn($method) ? 'return ' : ''; + $methods .= $cast . ' parent::' . $method->getName() . "();\n"; + $methods .= ' }' . "\n\n"; + } + + $invokeParamsString = implode(', ', $this->getParameterNamesForInvoke($method->getParameters())); + $callParamsString = implode(', ', $this->getParameterNamesForParentCall($method->getParameters())); + + $methods .= "\n \$this->__initializer__ " + . '&& $this->__initializer__->__invoke($this, ' . var_export($name, true) + . ', [' . $invokeParamsString . ']);' + . "\n\n " + . ($this->shouldProxiedMethodReturn($method) ? 'return ' : '') + . 'parent::' . $name . '(' . $callParamsString . ');' + . "\n" . ' }' . "\n"; + } + + return $methods; + } + + /** + * Generates the Proxy file name. + * + * @param string $className + * @param string $baseDirectory Optional base directory for proxy file name generation. + * If not specified, the directory configured on the Configuration of the + * EntityManager will be used by this factory. + * + * @return string + * + * @psalm-param class-string $className + */ + public function getProxyFileName($className, $baseDirectory = null) + { + $baseDirectory = $baseDirectory ?: $this->proxyDirectory; + + return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . Proxy::MARKER + . str_replace('\\', '', $className) . '.php'; + } + + /** + * Checks if the method is a short identifier getter. + * + * What does this mean? For proxy objects the identifier is already known, + * however accessing the getter for this identifier usually triggers the + * lazy loading, leading to a query that may not be necessary if only the + * ID is interesting for the userland code (for example in views that + * generate links to the entity, but do not display anything else). + * + * @param ReflectionMethod $method + * + * @return bool + */ + private function isShortIdentifierGetter($method, ClassMetadata $class) + { + $identifier = lcfirst(substr($method->getName(), 3)); + $startLine = $method->getStartLine(); + $endLine = $method->getEndLine(); + $cheapCheck = $method->getNumberOfParameters() === 0 + && substr($method->getName(), 0, 3) === 'get' + && in_array($identifier, $class->getIdentifier(), true) + && $class->hasField($identifier) + && ($endLine - $startLine <= 4); + + if ($cheapCheck) { + $code = file($method->getFileName()); + $code = trim(implode(' ', array_slice($code, $startLine - 1, $endLine - $startLine + 1))); + + $pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier); + + if (preg_match($pattern, $code)) { + return true; + } + } + + return false; + } + + /** + * Generates the list of public properties to be lazy loaded. + * + * @return array<int, string> + */ + private function getLazyLoadedPublicPropertiesNames(ClassMetadata $class): array + { + $properties = []; + + foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { + $name = $property->getName(); + + if ((! $class->hasField($name) && ! $class->hasAssociation($name)) || $class->isIdentifier($name)) { + continue; + } + + $properties[] = $name; + } + + return $properties; + } + + /** + * Generates the list of default values of public properties. + * + * @return mixed[] + */ + private function getLazyLoadedPublicProperties(ClassMetadata $class) + { + $defaultProperties = $class->getReflectionClass()->getDefaultProperties(); + $lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class); + $defaultValues = []; + + foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { + $name = $property->getName(); + + if (! in_array($name, $lazyLoadedPublicProperties, true)) { + continue; + } + + if (array_key_exists($name, $defaultProperties)) { + $defaultValues[$name] = $defaultProperties[$name]; + } elseif (method_exists($property, 'getType')) { + $propertyType = $property->getType(); + if ($propertyType !== null && $propertyType->allowsNull()) { + $defaultValues[$name] = null; + } + } + } + + return $defaultValues; + } + + /** + * @param ReflectionParameter[] $parameters + * @param string[] $renameParameters + * + * @return string + */ + private function buildParametersString(array $parameters, array $renameParameters = []) + { + $parameterDefinitions = []; + + $i = -1; + foreach ($parameters as $param) { + assert($param instanceof ReflectionParameter); + $i++; + $parameterDefinition = ''; + $parameterType = $this->getParameterType($param); + + if ($parameterType !== null) { + $parameterDefinition .= $parameterType . ' '; + } + + if ($param->isPassedByReference()) { + $parameterDefinition .= '&'; + } + + if ($param->isVariadic()) { + $parameterDefinition .= '...'; + } + + $parameterDefinition .= '$' . ($renameParameters ? $renameParameters[$i] : $param->getName()); + + if ($param->isDefaultValueAvailable()) { + $parameterDefinition .= ' = ' . var_export($param->getDefaultValue(), true); + } + + $parameterDefinitions[] = $parameterDefinition; + } + + return implode(', ', $parameterDefinitions); + } + + /** + * @return string|null + */ + private function getParameterType(ReflectionParameter $parameter) + { + if (! $parameter->hasType()) { + return null; + } + + $declaringFunction = $parameter->getDeclaringFunction(); + + assert($declaringFunction instanceof ReflectionMethod); + + return $this->formatType($parameter->getType(), $declaringFunction, $parameter); + } + + /** + * @param ReflectionParameter[] $parameters + * + * @return string[] + */ + private function getParameterNamesForInvoke(array $parameters) + { + return array_map( + static function (ReflectionParameter $parameter) { + return '$' . $parameter->getName(); + }, + $parameters + ); + } + + /** + * @param ReflectionParameter[] $parameters + * + * @return string[] + */ + private function getParameterNamesForParentCall(array $parameters) + { + return array_map( + static function (ReflectionParameter $parameter) { + $name = ''; + + if ($parameter->isVariadic()) { + $name .= '...'; + } + + $name .= '$' . $parameter->getName(); + + return $name; + }, + $parameters + ); + } + + /** + * @return string + */ + private function getMethodReturnType(ReflectionMethod $method) + { + if (! $method->hasReturnType()) { + return ''; + } + + return ': ' . $this->formatType($method->getReturnType(), $method); + } + + /** + * @return bool + */ + private function shouldProxiedMethodReturn(ReflectionMethod $method) + { + if (! $method->hasReturnType()) { + return true; + } + + return strtolower($this->formatType($method->getReturnType(), $method)) !== 'void'; + } + + /** + * @return string + */ + private function formatType( + ReflectionType $type, + ReflectionMethod $method, + ?ReflectionParameter $parameter = null + ) { + if ($type instanceof ReflectionUnionType) { + return implode('|', array_map( + function (ReflectionType $unionedType) use ($method, $parameter) { + return $this->formatType($unionedType, $method, $parameter); + }, + $type->getTypes() + )); + } + + assert($type instanceof ReflectionNamedType); + + $name = $type->getName(); + $nameLower = strtolower($name); + + if ($nameLower === 'static') { + $name = 'static'; + } + + if ($nameLower === 'self') { + $name = $method->getDeclaringClass()->getName(); + } + + if ($nameLower === 'parent') { + $name = $method->getDeclaringClass()->getParentClass()->getName(); + } + + if (! $type->isBuiltin() && ! class_exists($name) && ! interface_exists($name) && $name !== 'static') { + if ($parameter !== null) { + throw UnexpectedValueException::invalidParameterTypeHint( + $method->getDeclaringClass()->getName(), + $method->getName(), + $parameter->getName() + ); + } + + throw UnexpectedValueException::invalidReturnTypeHint( + $method->getDeclaringClass()->getName(), + $method->getName() + ); + } + + if (! $type->isBuiltin() && $name !== 'static') { + $name = '\\' . $name; + } + + if ( + $type->allowsNull() + && ! in_array($name, ['mixed', 'null'], true) + && ($parameter === null || ! $parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== null) + ) { + $name = '?' . $name; + } + + return $name; + } +} + +interface_exists(ClassMetadata::class); diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php b/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php new file mode 100644 index 0000000..d220232 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php @@ -0,0 +1,112 @@ +<?php + +namespace Doctrine\Common\Util; + +use Doctrine\Persistence\Proxy; +use ReflectionClass; + +use function get_class; +use function get_parent_class; +use function ltrim; +use function rtrim; +use function strrpos; +use function substr; + +/** + * Class and reflection related functionality for objects that + * might or not be proxy objects at the moment. + */ +class ClassUtils +{ + /** + * Gets the real class name of a class name that could be a proxy. + * + * @param string $className + * + * @return string + * + * @psalm-param class-string $className + * @psalm-return class-string + */ + public static function getRealClass($className) + { + $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); + + if ($pos === false) { + return $className; + } + + return substr($className, $pos + Proxy::MARKER_LENGTH + 2); + } + + /** + * Gets the real class name of an object (even if its a proxy). + * + * @param object $object + * + * @return string + * + * @psalm-return class-string + */ + public static function getClass($object) + { + return self::getRealClass(get_class($object)); + } + + /** + * Gets the real parent class name of a class or object. + * + * @param string $className + * + * @return string + * + * @psalm-param class-string $className + * @psalm-return class-string + */ + public static function getParentClass($className) + { + return get_parent_class(self::getRealClass($className)); + } + + /** + * Creates a new reflection class. + * + * @param string $className + * + * @return ReflectionClass + * + * @psalm-param class-string $className + */ + public static function newReflectionClass($className) + { + return new ReflectionClass(self::getRealClass($className)); + } + + /** + * Creates a new reflection object. + * + * @param object $object + * + * @return ReflectionClass + */ + public static function newReflectionObject($object) + { + return self::newReflectionClass(self::getClass($object)); + } + + /** + * Given a class name and a proxy namespace returns the proxy name. + * + * @param string $className + * @param string $proxyNamespace + * + * @return string + * + * @psalm-param class-string $className + * @psalm-return class-string + */ + public static function generateProxyClassName($className, $proxyNamespace) + { + return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\'); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php b/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php new file mode 100644 index 0000000..d21f700 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php @@ -0,0 +1,185 @@ +<?php + +namespace Doctrine\Common\Util; + +use ArrayIterator; +use ArrayObject; +use DateTimeInterface; +use Doctrine\Common\Collections\Collection; +use Doctrine\Persistence\Proxy; +use stdClass; + +use function array_keys; +use function count; +use function end; +use function explode; +use function extension_loaded; +use function get_class; +use function html_entity_decode; +use function ini_get; +use function ini_set; +use function is_array; +use function is_object; +use function method_exists; +use function ob_end_clean; +use function ob_get_contents; +use function ob_start; +use function spl_object_hash; +use function strip_tags; +use function var_dump; + +/** + * Static class containing most used debug methods. + * + * @deprecated The Debug class is deprecated, please use symfony/var-dumper instead. + * + * @link www.doctrine-project.org + */ +final class Debug +{ + /** + * Private constructor (prevents instantiation). + */ + private function __construct() + { + } + + /** + * Prints a dump of the public, protected and private properties of $var. + * + * @link https://xdebug.org/ + * + * @param mixed $var The variable to dump. + * @param int $maxDepth The maximum nesting level for object properties. + * @param bool $stripTags Whether output should strip HTML tags. + * @param bool $echo Send the dumped value to the output buffer + * + * @return string + */ + public static function dump($var, $maxDepth = 2, $stripTags = true, $echo = true) + { + $html = ini_get('html_errors'); + + if ($html !== true) { + ini_set('html_errors', 'on'); + } + + if (extension_loaded('xdebug')) { + ini_set('xdebug.var_display_max_depth', $maxDepth); + } + + $var = self::export($var, $maxDepth); + + ob_start(); + var_dump($var); + + $dump = ob_get_contents(); + + ob_end_clean(); + + $dumpText = ($stripTags ? strip_tags(html_entity_decode($dump)) : $dump); + + ini_set('html_errors', $html); + + if ($echo) { + echo $dumpText; + } + + return $dumpText; + } + + /** + * @param mixed $var + * @param int $maxDepth + * + * @return mixed + */ + public static function export($var, $maxDepth) + { + $return = null; + $isObj = is_object($var); + + if ($var instanceof Collection) { + $var = $var->toArray(); + } + + if (! $maxDepth) { + return is_object($var) ? get_class($var) + : (is_array($var) ? 'Array(' . count($var) . ')' : $var); + } + + if (is_array($var)) { + $return = []; + + foreach ($var as $k => $v) { + $return[$k] = self::export($v, $maxDepth - 1); + } + + return $return; + } + + if (! $isObj) { + return $var; + } + + $return = new stdClass(); + if ($var instanceof DateTimeInterface) { + $return->__CLASS__ = get_class($var); + $return->date = $var->format('c'); + $return->timezone = $var->getTimezone()->getName(); + + return $return; + } + + $return->__CLASS__ = ClassUtils::getClass($var); + + if ($var instanceof Proxy) { + $return->__IS_PROXY__ = true; + $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); + } + + if ($var instanceof ArrayObject || $var instanceof ArrayIterator) { + $return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1); + } + + return self::fillReturnWithClassAttributes($var, $return, $maxDepth); + } + + /** + * Fill the $return variable with class attributes + * Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075} + * + * @param object $var + * @param int $maxDepth + * + * @return mixed + */ + private static function fillReturnWithClassAttributes($var, stdClass $return, $maxDepth) + { + $clone = (array) $var; + + foreach (array_keys($clone) as $key) { + $aux = explode("\0", $key); + $name = end($aux); + if ($aux[0] === '') { + $name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private'); + } + + $return->$name = self::export($clone[$key], $maxDepth - 1); + } + + return $return; + } + + /** + * Returns a string representation of an object. + * + * @param object $obj + * + * @return string + */ + public static function toString($obj) + { + return method_exists($obj, '__toString') ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj); + } +} |