From 745cf2431a71d0e6c5f08f8605839279b2f7496e Mon Sep 17 00:00:00 2001 From: Devian Date: Thu, 22 Apr 2021 17:03:46 +0800 Subject: Initiate commit --- vendor/doctrine/common/.doctrine-project.json | 38 + vendor/doctrine/common/LICENSE | 19 + vendor/doctrine/common/README.md | 12 + vendor/doctrine/common/UPGRADE_TO_2_1 | 39 + vendor/doctrine/common/UPGRADE_TO_2_2 | 61 + vendor/doctrine/common/composer.json | 43 + vendor/doctrine/common/docs/en/index.rst | 10 + .../common/docs/en/reference/class-loading.rst | 242 ++++ vendor/doctrine/common/humbug.json.dist | 11 + .../common/lib/Doctrine/Common/ClassLoader.php | 289 +++++ .../common/lib/Doctrine/Common/CommonException.php | 14 + .../common/lib/Doctrine/Common/Comparable.php | 26 + .../Doctrine/Common/Proxy/AbstractProxyFactory.php | 230 ++++ .../lib/Doctrine/Common/Proxy/Autoloader.php | 100 ++ .../Proxy/Exception/InvalidArgumentException.php | 113 ++ .../Proxy/Exception/OutOfBoundsException.php | 28 + .../Common/Proxy/Exception/ProxyException.php | 12 + .../Proxy/Exception/UnexpectedValueException.php | 74 ++ .../common/lib/Doctrine/Common/Proxy/Proxy.php | 65 ++ .../lib/Doctrine/Common/Proxy/ProxyDefinition.php | 42 + .../lib/Doctrine/Common/Proxy/ProxyGenerator.php | 1194 ++++++++++++++++++++ .../common/lib/Doctrine/Common/Util/ClassUtils.php | 112 ++ .../common/lib/Doctrine/Common/Util/Debug.php | 185 +++ vendor/doctrine/common/phpstan.neon.dist | 49 + vendor/doctrine/common/psalm.xml | 16 + 25 files changed, 3024 insertions(+) create mode 100644 vendor/doctrine/common/.doctrine-project.json create mode 100644 vendor/doctrine/common/LICENSE create mode 100644 vendor/doctrine/common/README.md create mode 100644 vendor/doctrine/common/UPGRADE_TO_2_1 create mode 100644 vendor/doctrine/common/UPGRADE_TO_2_2 create mode 100644 vendor/doctrine/common/composer.json create mode 100644 vendor/doctrine/common/docs/en/index.rst create mode 100644 vendor/doctrine/common/docs/en/reference/class-loading.rst create mode 100644 vendor/doctrine/common/humbug.json.dist create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/CommonException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Comparable.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php create mode 100644 vendor/doctrine/common/phpstan.neon.dist create mode 100644 vendor/doctrine/common/psalm.xml (limited to 'vendor/doctrine/common') diff --git a/vendor/doctrine/common/.doctrine-project.json b/vendor/doctrine/common/.doctrine-project.json new file mode 100644 index 0000000..1f33c55 --- /dev/null +++ b/vendor/doctrine/common/.doctrine-project.json @@ -0,0 +1,38 @@ +{ + "active": true, + "name": "Common", + "slug": "common", + "docsSlug": "doctrine-common", + "versions": [ + { + "name": "3.1", + "branchName": "3.1.x", + "slug": "3.1", + "upcoming": true + }, + { + "name": "3.0", + "branchName": "3.0.x", + "slug": "3.0", + "current": true + }, + { + "name": "2.13", + "branchName": "2.13.x", + "slug": "2.13", + "maintained": false + }, + { + "name": "2.12", + "branchName": "2.12.x", + "slug": "2.12", + "maintained": false + }, + { + "name": "2.11", + "branchName": "2.11", + "slug": "2.11", + "maintained": false + } + ] +} diff --git a/vendor/doctrine/common/LICENSE b/vendor/doctrine/common/LICENSE new file mode 100644 index 0000000..8c38cc1 --- /dev/null +++ b/vendor/doctrine/common/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2015 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/common/README.md b/vendor/doctrine/common/README.md new file mode 100644 index 0000000..603c38f --- /dev/null +++ b/vendor/doctrine/common/README.md @@ -0,0 +1,12 @@ +# Doctrine Common + +[![Build Status](https://github.com/doctrine/common/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/common/actions) +[![codecov](https://codecov.io/gh/doctrine/common/branch/3.1.x/graph/badge.svg)](https://codecov.io/gh/doctrine/common) + +The Doctrine Common project is a library that provides extensions to core PHP functionality. + +## More resources: + +* [Website](https://www.doctrine-project.org/) +* [Documentation](https://www.doctrine-project.org/projects/doctrine-common/en/latest/) +* [Downloads](https://github.com/doctrine/common/releases) diff --git a/vendor/doctrine/common/UPGRADE_TO_2_1 b/vendor/doctrine/common/UPGRADE_TO_2_1 new file mode 100644 index 0000000..891a2e5 --- /dev/null +++ b/vendor/doctrine/common/UPGRADE_TO_2_1 @@ -0,0 +1,39 @@ +This document details all the possible changes that you should investigate when updating +your project from Doctrine Common 2.0.x to 2.1 + +## AnnotationReader changes + +The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way: + + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + // new code necessary starting here + $reader->setIgnoreNotImportedAnnotations(true); + $reader->setEnableParsePhpImports(false); + $reader = new \Doctrine\Common\Annotations\CachedReader( + new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() + ); + +## Annotation Base class or @Annotation + +Beginning after 2.1-RC2 you have to either extend ``Doctrine\Common\Annotations\Annotation`` or add @Annotation to your annotations class-level docblock, otherwise the class will simply be ignored. + +## Removed methods on AnnotationReader + +* AnnotationReader::setAutoloadAnnotations() +* AnnotationReader::getAutoloadAnnotations() +* AnnotationReader::isAutoloadAnnotations() + +## AnnotationRegistry + +Autoloading through the PHP autoloader is removed from the 2.1 AnnotationReader. Instead you have to use the global AnnotationRegistry for loading purposes: + + \Doctrine\Common\Annotations\AnnotationRegistry::registerFile($fileWithAnnotations); + \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace($namespace, $dirs = null); + \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespaces($namespaces); + \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($callable); + +The $callable for registering a loader accepts a class as first and only parameter and must try to silently autoload it. On success true has to be returned. +The registerAutoloadNamespace function registers a PSR-0 compatible silent autoloader for all classes with the given namespace in the given directories. +If null is passed as directory the include path will be used. + diff --git a/vendor/doctrine/common/UPGRADE_TO_2_2 b/vendor/doctrine/common/UPGRADE_TO_2_2 new file mode 100644 index 0000000..1d93a13 --- /dev/null +++ b/vendor/doctrine/common/UPGRADE_TO_2_2 @@ -0,0 +1,61 @@ +This document details all the possible changes that you should investigate when +updating your project from Doctrine Common 2.1 to 2.2: + +## Annotation Changes + +- AnnotationReader::setIgnoreNotImportedAnnotations has been removed, you need to + add ignore annotation names which are supposed to be ignored via + AnnotationReader::addGlobalIgnoredName + +- AnnotationReader::setAutoloadAnnotations was deprecated by the AnnotationRegistry + in 2.1 and has been removed in 2.2 + +- AnnotationReader::setEnableParsePhpImports was added to ease transition to the new + annotation mechanism in 2.1 and is removed in 2.2 + +- AnnotationReader::isParsePhpImportsEnabled is removed (see above) + +- AnnotationReader::setDefaultAnnotationNamespace was deprecated in favor of explicit + configuration in 2.1 and will be removed in 2.2 (for isolated projects where you + have full-control over _all_ available annotations, we offer a dedicated reader + class ``SimpleAnnotationReader``) + +- AnnotationReader::setAnnotationCreationFunction was deprecated in 2.1 and will be + removed in 2.2. We only offer two creation mechanisms which cannot be changed + anymore to allow the same reader instance to work with all annotations regardless + of which library they are coming from. + +- AnnotationReader::setAnnotationNamespaceAlias was deprecated in 2.1 and will be + removed in 2.2 (see setDefaultAnnotationNamespace) + +- If you use a class as annotation which has not the @Annotation marker in it's + class block, we will now throw an exception instead of silently ignoring it. You + can however still achieve the previous behavior using the @IgnoreAnnotation, or + AnnotationReader::addGlobalIgnoredName (the exception message will contain detailed + instructions when you run into this problem). + +## Cache Changes + +- Renamed old AbstractCache to CacheProvider + +- Dropped the support to the following functions of all cache providers: + + - CacheProvider::deleteByWildcard + + - CacheProvider::deleteByRegEx + + - CacheProvider::deleteByPrefix + + - CacheProvider::deleteBySuffix + +- CacheProvider::deleteAll will not remove ALL entries, it will only mark them as invalid + +- CacheProvider::flushAll will remove ALL entries, namespaced or not + +- Added support to MemcachedCache + +- Added support to WincacheCache + +## ClassLoader Changes + +- ClassLoader::fileExistsInIncludePath() no longer exists. Use the native stream_resolve_include_path() PHP function \ No newline at end of file diff --git a/vendor/doctrine/common/composer.json b/vendor/doctrine/common/composer.json new file mode 100644 index 0000000..0f14ca3 --- /dev/null +++ b/vendor/doctrine/common/composer.json @@ -0,0 +1,43 @@ +{ + "name": "doctrine/common", + "type": "library", + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", + "keywords": [ + "php", + "common", + "doctrine" + ], + "homepage": "https://www.doctrine-project.org/projects/common.html", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}, + {"name": "Marco Pivetta", "email": "ocramius@gmail.com"} + ], + "require": { + "php": "^7.1 || ^8.0", + "doctrine/persistence": "^2.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", + "doctrine/coding-standard": "^6.0 || ^8.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^4.0.5", + "vimeo/psalm": "^4.4" + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\": "tests/Doctrine/Tests" + } + } +} diff --git a/vendor/doctrine/common/docs/en/index.rst b/vendor/doctrine/common/docs/en/index.rst new file mode 100644 index 0000000..7550d8b --- /dev/null +++ b/vendor/doctrine/common/docs/en/index.rst @@ -0,0 +1,10 @@ +Common Documentation +==================== + +Welcome to the Doctrine Common Library documentation. + +.. toctree:: + :depth: 2 + :glob: + + * diff --git a/vendor/doctrine/common/docs/en/reference/class-loading.rst b/vendor/doctrine/common/docs/en/reference/class-loading.rst new file mode 100644 index 0000000..e193b46 --- /dev/null +++ b/vendor/doctrine/common/docs/en/reference/class-loading.rst @@ -0,0 +1,242 @@ +Class Loading +============= + +Class loading is an essential part of any PHP application that +makes heavy use of classes and interfaces. Unfortunately, a lot of +people and projects spend a lot of time and effort on custom and +specialized class loading strategies. It can quickly become a pain +to understand what is going on when using multiple libraries and/or +frameworks, each with its own way to do class loading. Class +loading should be simple and it is an ideal candidate for +convention over configuration. + +Overview +-------- + +The Doctrine Common ClassLoader implements a simple and efficient +approach to class loading that is easy to understand and use. The +implementation is based on the widely used and accepted convention +of mapping namespace and class names to a directory structure. This +approach is used for example by Symfony2, the Zend Framework and of +course, Doctrine. + +For example, the following class: + +.. code-block:: php + + register(); + $dbalLoader->register(); + $ormLoader->register(); + +Do not be afraid of using multiple class loaders. Due to the +efficient class loading design you will not incur much overhead +from using many class loaders. Take a look at the implementation of +``ClassLoader#loadClass`` to see how simple and efficient the class +loading is. The iteration over the installed class loaders happens +in C (with the exception of using ``ClassLoader::classExists``). + +A ClassLoader can be used in the following other variations, +however, these are rarely used/needed: + + +- If only the second argument is not supplied, the class loader + will be responsible for the namespace prefix given in the first + argument and it will rely on the PHP include_path. + +- If only the first argument is not supplied, the class loader + will be responsible for *all* classes and it will try to look up + *all* classes starting at the directory given as the second + argument. + +- If both arguments are not supplied, the class loader will be + responsible for *all* classes and it will rely on the PHP + include_path. + + +File Extension +-------------- + +By default, a ClassLoader uses the ``.php`` file extension for all +class files. You can change this behavior, for example to use a +ClassLoader to load classes from a library that uses the +".class.php" convention (but it must nevertheless adhere to the +directory structure convention!): + +.. code-block:: php + + setFileExtension('.class.php'); + $customLoader->register(); + +Namespace Separator +------------------- + +By default, a ClassLoader uses the ``\`` namespace separator. You +can change this behavior, for example to use a ClassLoader to load +legacy Zend Framework classes that still use the underscore "_" +separator: + +.. code-block:: php + + setNamespaceSeparator('_'); + $zend1Loader->register(); + +Failing Silently and class_exists +---------------------------------- + +A lot of class/autoloaders these days try to fail silently when a +class file is not found. For the most part this is necessary in +order to support using ``class_exists('ClassName', true)`` which is +supposed to return a boolean value but triggers autoloading. This +is a bad thing as it basically forces class loaders to fail +silently, which in turn requires costly file_exists or fopen calls +for each class being loaded, even though in at least 99% of the +cases this is not necessary (compare the number of +class_exists(..., true) invocations to the total number of classes +being loaded in a request). + +The Doctrine Common ClassLoader does not fail silently, by design. +It therefore does not need any costly checks for file existence. A +ClassLoader is always responsible for all classes with a certain +namespace prefix and if a class is requested to be loaded and can +not be found this is considered to be a fatal error. This also +means that using class_exists(..., true) to check for class +existence when using a Doctrine Common ClassLoader is not possible +but this is not a bad thing. What class\_exists(..., true) actually +means is two things: 1) Check whether the class is already +defined/exists (i.e. class_exists(..., false)) and if not 2) check +whether a class file can be loaded for that class. In the Doctrine +Common ClassLoader the two responsibilities of loading a class and +checking for its existence are separated, which can be observed by +the existence of the two methods ``loadClass`` and +``canLoadClass``. Thereby ``loadClass`` does not invoke +``canLoadClass`` internally, by design. However, you are free to +use it yourself to check whether a class can be loaded and the +following code snippet is thus equivalent to class\_exists(..., +true): + +.. code-block:: php + + canLoadClass('Foo')) { + // ... + } + +The only problem with this is that it is inconvenient as you need +to have a reference to the class loaders around (and there are +often multiple class loaders in use). Therefore, a simpler +alternative exists for the cases in which you really want to ask +all installed class loaders whether they can load the class: +``ClassLoader::classExists($className)``: + +.. code-block:: php + + ClassLoader 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 include_path. + * + * @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 ClassLoader 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 ClassLoader, {@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 ClassLoader, 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 ClassLoader 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 ClassLoader for the class or NULL if no such ClassLoader 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 @@ +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 $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 @@ + 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 @@ + */ + public $identifierFields; + + /** @var ReflectionProperty[] */ + public $reflectionFields; + + /** @var callable */ + public $initializer; + + /** @var callable */ + public $cloner; + + /** + * @param string $proxyClassName + * @param array $identifierFields + * @param array $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 @@ +%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 = '; + +/** + * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE\'S PROXY GENERATOR + */ +class extends \ implements \ +{ + /** + * @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 properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = ; + + /** + * @var array default values of properties to be lazy loaded, with keys being the property names + * + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties + */ + public static $lazyPropertiesDefaults = ; + + + + + + + + + + + + + + + + + + /** + * 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; + } + + +} +'; + + /** + * Initializes a new instance of the ProxyFactory class that is + * connected to the given EntityManager. + * + * @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 = <<__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(<<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 = <<__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 = <<__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 = <<__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 . <<__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 = <<__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 <<__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 + */ + 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 @@ +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); + } +} diff --git a/vendor/doctrine/common/phpstan.neon.dist b/vendor/doctrine/common/phpstan.neon.dist new file mode 100644 index 0000000..e63c669 --- /dev/null +++ b/vendor/doctrine/common/phpstan.neon.dist @@ -0,0 +1,49 @@ +parameters: + phpVersion: 70100 + level: 3 + paths: + - lib + - tests + excludes_analyse: + - lib/vendor/doctrine-build-common + - tests/Doctrine/Tests/Common/Proxy/InvalidReturnTypeClass.php + - tests/Doctrine/Tests/Common/Proxy/InvalidTypeHintClass.php + - tests/Doctrine/Tests/Common/Proxy/LazyLoadableObjectWithTypedProperties.php + - tests/Doctrine/Tests/Common/Proxy/MagicIssetClassWithInteger.php + - tests/Doctrine/Tests/Common/Proxy/NullableNonOptionalHintClass.php + - tests/Doctrine/Tests/Common/Proxy/Php8UnionTypes.php + - tests/Doctrine/Tests/Common/Proxy/ProxyGeneratorTest.php + - tests/Doctrine/Tests/Common/Proxy/ProxyLogicTypedPropertiesTest.php + - tests/Doctrine/Tests/Common/Proxy/SerializedClass.php + - tests/Doctrine/Tests/Common/Proxy/VariadicTypeHintClass.php + - tests/Doctrine/Tests/Common/Proxy/generated + ignoreErrors: + - '#Access to an undefined property Doctrine\\Common\\Proxy\\Proxy::\$publicField#' + - + message: '#^Result of method Doctrine\\Tests\\Common\\Proxy\\LazyLoadableObjectWithVoid::(adding|incrementing)AndReturningVoid\(\) \(void\) is used\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' + - + message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicTest.php' + - + message: '#^Access to an undefined property Doctrine\\Common\\Proxy\\Proxy&Doctrine\\Tests\\Common\\Proxy\\LazyLoadableObject::\$non_existing_property\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicTest.php' + - + message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicTest.php' + - + message: '#^Instantiated class Doctrine\\Tests\\Common\\ProxyProxy\\__CG__\\Doctrine\\Tests\\Common\\Proxy\\.* not found.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' + - + message: '#^Property Doctrine\\Tests\\Common\\Proxy\\ProxyLogicVoidReturnTypeTest::\$initializerCallbackMock \(callable\(\): mixed&PHPUnit\\Framework\\MockObject\\MockObject\) does not accept PHPUnit\\Framework\\MockObject\\MockObject&stdClass\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyLogicVoidReturnTypeTest.php' + - + message: '#^Method Doctrine\\Tests\\Common\\Proxy\\MagicIssetClassWithInteger::__isset\(\) should return bool but returns int\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/MagicIssetClassWithInteger.php' + - + message: '#^Access to an undefined property Doctrine\\Tests\\Common\\Proxy\\MagicGetByRefClass\:\:\$nonExisting\.$#' + path: 'tests/Doctrine/Tests/Common/Proxy/ProxyMagicMethodsTest.php' + +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/vendor/doctrine/common/psalm.xml b/vendor/doctrine/common/psalm.xml new file mode 100644 index 0000000..f49326f --- /dev/null +++ b/vendor/doctrine/common/psalm.xml @@ -0,0 +1,16 @@ + + + + + + + + + -- cgit v1.2.3