This commit is contained in:
emmymayo
2025-02-05 23:15:46 +01:00
commit 7269c99357
16995 changed files with 3389680 additions and 0 deletions
@@ -0,0 +1 @@
<?php
@@ -0,0 +1,106 @@
<?php
namespace MailPoetVendor\Doctrine\Common;
if (!defined('ABSPATH')) exit;
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);
class ClassLoader
{
protected $fileExtension = '.php';
protected $namespace;
protected $includePath;
protected $namespaceSeparator = '\\';
public function __construct($ns = null, $includePath = null)
{
$this->namespace = $ns;
$this->includePath = $includePath;
}
public function setNamespaceSeparator($sep)
{
$this->namespaceSeparator = $sep;
}
public function getNamespaceSeparator()
{
return $this->namespaceSeparator;
}
public function setIncludePath($includePath)
{
$this->includePath = $includePath;
}
public function getIncludePath()
{
return $this->includePath;
}
public function setFileExtension($fileExtension)
{
$this->fileExtension = $fileExtension;
}
public function getFileExtension()
{
return $this->fileExtension;
}
public function register()
{
spl_autoload_register([$this, 'loadClass']);
}
public function unregister()
{
spl_autoload_unregister([$this, 'loadClass']);
}
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);
}
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;
}
public static function classExists($className)
{
return self::typeExists($className, \true);
}
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;
}
private static function typeExists($type, $autoload = \false)
{
return class_exists($type, $autoload) || interface_exists($type, $autoload) || trait_exists($type, $autoload);
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common;
if (!defined('ABSPATH')) exit;
use Exception;
class CommonException extends Exception
{
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common;
if (!defined('ABSPATH')) exit;
interface Comparable
{
public function compareTo($other);
}
@@ -0,0 +1,109 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Proxy\Exception\InvalidArgumentException;
use MailPoetVendor\Doctrine\Common\Proxy\Exception\OutOfBoundsException;
use MailPoetVendor\Doctrine\Common\Util\ClassUtils;
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata;
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadataFactory;
use function class_exists;
use function file_exists;
use function filemtime;
use function in_array;
abstract class AbstractProxyFactory
{
public const AUTOGENERATE_NEVER = 0;
public const AUTOGENERATE_ALWAYS = 1;
public const AUTOGENERATE_FILE_NOT_EXISTS = 2;
public const AUTOGENERATE_EVAL = 3;
public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED = 4;
private const AUTOGENERATE_MODES = [self::AUTOGENERATE_NEVER, self::AUTOGENERATE_ALWAYS, self::AUTOGENERATE_FILE_NOT_EXISTS, self::AUTOGENERATE_EVAL, self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED];
private $metadataFactory;
private $proxyGenerator;
private $autoGenerate;
private $definitions = [];
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);
}
}
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;
}
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;
}
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;
}
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;
case self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED:
if (!file_exists($fileName) || filemtime($fileName) < filemtime($classMetadata->getReflectionClass()->getFileName())) {
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
}
require $fileName;
break;
}
}
return $this->definitions[$className];
}
protected abstract function skipClass(ClassMetadata $metadata);
protected abstract function createProxyDefinition($className);
}
@@ -0,0 +1,51 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy;
if (!defined('ABSPATH')) exit;
use Closure;
use MailPoetVendor\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;
class Autoloader
{
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';
}
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;
}
}
@@ -0,0 +1,53 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Persistence\Proxy;
use InvalidArgumentException as BaseInvalidArgumentException;
use function get_class;
use function gettype;
use function is_object;
use function sprintf;
class InvalidArgumentException extends BaseInvalidArgumentException implements ProxyException
{
public static function proxyDirectoryRequired()
{
return new self('You must configure a proxy directory. See docs for details');
}
public static function notProxyClass($className, $proxyNamespace)
{
return new self(sprintf('The class "%s" is not part of the proxy namespace "%s"', $className, $proxyNamespace));
}
public static function invalidPlaceholder($name)
{
return new self(sprintf('Provided placeholder for "%s" must be either a string or a valid callable', $name));
}
public static function proxyNamespaceRequired()
{
return new self('You must configure a proxy namespace');
}
public static function unitializedProxyExpected(Proxy $proxy)
{
return new self(sprintf('Provided proxy of type "%s" must not be initialized.', get_class($proxy)));
}
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));
}
public static function classMustNotBeAbstract($className)
{
return new self(sprintf('Unable to create a proxy for an abstract class "%s".', $className));
}
public static function classMustNotBeFinal($className)
{
return new self(sprintf('Unable to create a proxy for a final class "%s".', $className));
}
public static function classMustNotBeReadOnly($className)
{
return new self(sprintf('Unable to create a proxy for a readonly class "%s".', $className));
}
public static function invalidAutoGenerateMode($value) : self
{
return new self(sprintf('Invalid auto generate mode "%s" given.', $value));
}
}
@@ -0,0 +1,12 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
if (!defined('ABSPATH')) exit;
use OutOfBoundsException as BaseOutOfBoundsException;
use function sprintf;
class OutOfBoundsException extends BaseOutOfBoundsException implements ProxyException
{
public static function missingPrimaryKeyValue($className, $idField)
{
return new self(sprintf('Missing value for primary key %s on %s', $idField, $className));
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
if (!defined('ABSPATH')) exit;
interface ProxyException
{
}
@@ -0,0 +1,21 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
if (!defined('ABSPATH')) exit;
use Throwable;
use UnexpectedValueException as BaseUnexpectedValueException;
use function sprintf;
class UnexpectedValueException extends BaseUnexpectedValueException implements ProxyException
{
public static function proxyDirectoryNotWritable($proxyDirectory)
{
return new self(sprintf('Your proxy directory "%s" must be writable', $proxyDirectory));
}
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);
}
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);
}
}
@@ -0,0 +1,14 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy;
if (!defined('ABSPATH')) exit;
use Closure;
use MailPoetVendor\Doctrine\Persistence\Proxy as BaseProxy;
interface Proxy extends BaseProxy
{
public function __setInitialized($initialized);
public function __setInitializer(?Closure $initializer = null);
public function __getInitializer();
public function __setCloner(?Closure $cloner = null);
public function __getCloner();
public function __getLazyProperties();
}
@@ -0,0 +1,20 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy;
if (!defined('ABSPATH')) exit;
use ReflectionProperty;
class ProxyDefinition
{
public $proxyClassName;
public $identifierFields;
public $reflectionFields;
public $initializer;
public $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;
}
}
@@ -0,0 +1,733 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Proxy;
if (!defined('ABSPATH')) exit;
use BackedEnum;
use MailPoetVendor\Doctrine\Common\Proxy\Exception\InvalidArgumentException;
use MailPoetVendor\Doctrine\Common\Proxy\Exception\UnexpectedValueException;
use MailPoetVendor\Doctrine\Common\Util\ClassUtils;
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata;
use ReflectionIntersectionType;
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 array_unique;
use function assert;
use function bin2hex;
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 get_class;
use function implode;
use function in_array;
use function interface_exists;
use function is_callable;
use function is_dir;
use function is_scalar;
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 preg_replace;
use function preg_split;
use function random_bytes;
use function rename;
use function rtrim;
use function sprintf;
use function str_replace;
use function strpos;
use function strrev;
use function strtolower;
use function strtr;
use function substr;
use function trim;
use function var_export;
use const DIRECTORY_SEPARATOR;
use const PHP_VERSION_ID;
use const PREG_SPLIT_DELIM_CAPTURE;
class ProxyGenerator
{
public const PATTERN_MATCH_ID_METHOD = <<<'EOT'
((?(DEFINE)
(?<type>\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*)
(?<intersection_type>(?&type)\s*&\s*(?&type))
(?<union_type>(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type))(?:\s*\|\s*(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type)))+)
)(?:public\s+)?(?:function\s+%s\s*\(\)\s*)\s*(?::\s*(?:(?&union_type)|(?&intersection_type)|(?:\??(?&type)))\s*)?{\s*return\s*\$this->%s;\s*})i
EOT;
private $proxyNamespace;
private $proxyDirectory;
protected $placeholders = ['baseProxyInterface' => Proxy::class, 'additionalProperties' => ''];
protected $proxyClassTemplate = '<?php
namespace <namespace>;
<enumUseStatements>
class <proxyShortClassName> extends \\<className> implements \\<baseProxyInterface>
{
public $__initializer__;
public $__cloner__;
public $__isInitialized__ = false;
public static $lazyPropertiesNames = <lazyPropertiesNames>;
public static $lazyPropertiesDefaults = <lazyPropertiesDefaults>;
<additionalProperties>
<constructorImpl>
<magicGet>
<magicSet>
<magicIsset>
<sleepImpl>
<wakeupImpl>
<cloneImpl>
public function __load(): void
{
$this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', []);
}
public function __isInitialized(): bool
{
return $this->__isInitialized__;
}
public function __setInitialized($initialized): void
{
$this->__isInitialized__ = $initialized;
}
public function __setInitializer(?\\Closure $initializer = null): void
{
$this->__initializer__ = $initializer;
}
public function __getInitializer(): ?\\Closure
{
return $this->__initializer__;
}
public function __setCloner(?\\Closure $cloner = null): void
{
$this->__cloner__ = $cloner;
}
public function __getCloner(): ?\\Closure
{
return $this->__cloner__;
}
public function __getLazyProperties(): array
{
return self::$lazyPropertiesDefaults;
}
<methods>
}
';
public function __construct($proxyDirectory, $proxyNamespace)
{
if (!$proxyDirectory) {
throw InvalidArgumentException::proxyDirectoryRequired();
}
if (!$proxyNamespace) {
throw InvalidArgumentException::proxyNamespaceRequired();
}
$this->proxyDirectory = $proxyDirectory;
$this->proxyNamespace = $proxyNamespace;
}
public function setPlaceholder($name, $placeholder)
{
if (!is_string($placeholder) && !is_callable($placeholder)) {
throw InvalidArgumentException::invalidPlaceholder($name);
}
$this->placeholders[$name] = $placeholder;
}
public function setProxyClassTemplate($proxyClassTemplate)
{
$this->proxyClassTemplate = (string) $proxyClassTemplate;
}
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 . '.' . bin2hex(random_bytes(12));
file_put_contents($tmpFileName, $proxyCode);
@chmod($tmpFileName, 0664);
rename($tmpFileName, $fileName);
}
private function verifyClassCanBeProxied(ClassMetadata $class)
{
if ($class->getReflectionClass()->isFinal()) {
throw InvalidArgumentException::classMustNotBeFinal($class->getName());
}
if ($class->getReflectionClass()->isAbstract()) {
throw InvalidArgumentException::classMustNotBeAbstract($class->getName());
}
if (PHP_VERSION_ID >= 80200 && $class->getReflectionClass()->isReadOnly()) {
throw InvalidArgumentException::classMustNotBeReadOnly($class->getName());
}
}
private function generateProxyShortClassName(ClassMetadata $class)
{
$proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
$parts = explode('\\', strrev($proxyClassName), 2);
return strrev($parts[0]);
}
private function generateNamespace(ClassMetadata $class)
{
$proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
$parts = explode('\\', strrev($proxyClassName), 2);
return strrev($parts[1]);
}
public function generateEnumUseStatements(ClassMetadata $class) : string
{
if (PHP_VERSION_ID < 80100) {
return "\n";
}
$defaultProperties = $class->getReflectionClass()->getDefaultProperties();
$lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
$enumClasses = [];
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) && $defaultProperties[$name] instanceof BackedEnum) {
$enumClassNameParts = explode('\\', get_class($defaultProperties[$name]));
$enumClasses[] = $enumClassNameParts[0];
}
}
return implode("\n", array_map(static function ($className) {
return 'use ' . $className . ';';
}, array_unique($enumClasses))) . "\n";
}
private function generateClassName(ClassMetadata $class)
{
return ltrim($class->getName(), '\\');
}
private function generateLazyPropertiesNames(ClassMetadata $class)
{
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
$values = [];
foreach ($lazyPublicProperties as $name) {
$values[$name] = null;
}
return var_export($values, \true);
}
private function generateLazyPropertiesDefaults(ClassMetadata $class)
{
return var_export($this->getLazyLoadedPublicProperties($class), \true);
}
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;
}
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
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;
} elseif ($returnTypeHint === ': never') {
$magicGet .= <<<'EOT'
parent::__get($name);
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 }";
}
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
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;
} elseif ($returnTypeHint === ': never') {
$magicSet .= <<<'EOT'
parent::__set($name, $value);
EOT;
} else {
$magicSet .= <<<'EOT'
return parent::__set($name, $value);
EOT;
}
} else {
$magicSet .= ' $this->$name = $value;';
}
return $magicSet . "\n }";
}
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
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 }";
}
private function generateSleepImpl(ClassMetadata $class)
{
$reflectionClass = $class->getReflectionClass();
$hasParentSleep = $reflectionClass->hasMethod('__sleep');
$inheritDoc = $hasParentSleep ? '{@inheritDoc}' : '';
$returnTypeHint = $hasParentSleep ? $this->getMethodReturnType($reflectionClass->getMethod('__sleep')) : '';
$sleepImpl = <<<EOT
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() ? "\x00" . $prop->getDeclaringClass()->getName() . "\x00" . $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;
}
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
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;
}
private function generateCloneImpl(ClassMetadata $class)
{
$reflectionClass = $class->getReflectionClass();
$hasParentClone = $reflectionClass->hasMethod('__clone');
$returnTypeHint = $hasParentClone ? $this->getMethodReturnType($reflectionClass->getMethod('__clone')) : '';
$inheritDoc = $hasParentClone ? '{@inheritDoc}' : '';
$callParentClone = $hasParentClone ? "\n parent::__clone();\n" : '';
return <<<EOT
public function __clone(){$returnTypeHint}
{
\$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', []);
{$callParentClone} }
EOT;
}
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'], \true) ? '(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;
}
public function getProxyFileName($className, $baseDirectory = null)
{
$baseDirectory = $baseDirectory ?: $this->proxyDirectory;
return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . Proxy::MARKER . str_replace('\\', '', $className) . '.php';
}
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;
}
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;
}
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;
}
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());
$parameterDefinition .= $this->getParameterDefaultValue($param);
$parameterDefinitions[] = $parameterDefinition;
}
return implode(', ', $parameterDefinitions);
}
private function getParameterType(ReflectionParameter $parameter)
{
if (!$parameter->hasType()) {
return null;
}
$declaringFunction = $parameter->getDeclaringFunction();
assert($declaringFunction instanceof ReflectionMethod);
return $this->formatType($parameter->getType(), $declaringFunction, $parameter);
}
private function getParameterDefaultValue(ReflectionParameter $parameter)
{
if (!$parameter->isDefaultValueAvailable()) {
return '';
}
if (PHP_VERSION_ID < 80100 || is_scalar($parameter->getDefaultValue())) {
return ' = ' . var_export($parameter->getDefaultValue(), \true);
}
$value = rtrim(substr(explode('$' . $parameter->getName() . ' = ', (string) $parameter, 2)[1], 0, -2));
if (strpos($value, '\\') !== \false || strpos($value, '::') !== \false) {
$value = preg_split("/('(?:[^'\\\\]*+(?:\\\\.)*+)*+')/", $value, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($value as $i => $part) {
if ($i % 2 === 0) {
$value[$i] = preg_replace('/(?<![a-zA-Z0-9_\\x7f-\\xff\\\\])[a-zA-Z0-9_\\x7f-\\xff]++(?:\\\\[a-zA-Z0-9_\\x7f-\\xff]++|::)++/', '\\\\\\0', $part);
}
}
$value = implode('', $value);
}
return ' = ' . $value;
}
private function getParameterNamesForInvoke(array $parameters)
{
return array_map(static function (ReflectionParameter $parameter) {
return '$' . $parameter->getName();
}, $parameters);
}
private function getParameterNamesForParentCall(array $parameters)
{
return array_map(static function (ReflectionParameter $parameter) {
$name = '';
if ($parameter->isVariadic()) {
$name .= '...';
}
$name .= '$' . $parameter->getName();
return $name;
}, $parameters);
}
private function getMethodReturnType(ReflectionMethod $method)
{
if (!$method->hasReturnType()) {
return '';
}
return ': ' . $this->formatType($method->getReturnType(), $method);
}
private function shouldProxiedMethodReturn(ReflectionMethod $method)
{
if (!$method->hasReturnType()) {
return \true;
}
return !in_array(strtolower($this->formatType($method->getReturnType(), $method)), ['void', 'never'], \true);
}
private function formatType(ReflectionType $type, ReflectionMethod $method, ?ReflectionParameter $parameter = null)
{
if ($type instanceof ReflectionUnionType) {
return implode('|', array_map(function (ReflectionType $unionedType) use($method, $parameter) {
if ($unionedType instanceof ReflectionIntersectionType) {
return '(' . $this->formatType($unionedType, $method, $parameter) . ')';
}
return $this->formatType($unionedType, $method, $parameter);
}, $type->getTypes()));
}
if ($type instanceof ReflectionIntersectionType) {
return implode('&', array_map(function (ReflectionType $intersectedType) use($method, $parameter) {
return $this->formatType($intersectedType, $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;
}
}
@@ -0,0 +1,42 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Util;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\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 ClassUtils
{
public static function getRealClass($className)
{
$pos = strrpos($className, '\\' . Proxy::MARKER . '\\');
if ($pos === \false) {
return $className;
}
return substr($className, $pos + Proxy::MARKER_LENGTH + 2);
}
public static function getClass($object)
{
return self::getRealClass(get_class($object));
}
public static function getParentClass($className)
{
return get_parent_class(self::getRealClass($className));
}
public static function newReflectionClass($className)
{
return new ReflectionClass(self::getRealClass($className));
}
public static function newReflectionObject($object)
{
return self::newReflectionClass(self::getClass($object));
}
public static function generateProxyClassName($className, $proxyNamespace)
{
return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\');
}
}
@@ -0,0 +1,108 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Util;
if (!defined('ABSPATH')) exit;
use ArrayIterator;
use ArrayObject;
use DateTimeInterface;
use MailPoetVendor\Doctrine\Common\Collections\Collection;
use MailPoetVendor\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;
final class Debug
{
private function __construct()
{
}
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;
}
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);
}
private static function fillReturnWithClassAttributes($var, stdClass $return, $maxDepth)
{
$clone = (array) $var;
foreach (array_keys($clone) as $key) {
$aux = explode("\x00", $key);
$name = end($aux);
if ($aux[0] === '') {
$name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private');
}
$return->{$name} = self::export($clone[$key], $maxDepth - 1);
}
return $return;
}
public static function toString($obj)
{
return method_exists($obj, '__toString') ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj);
}
}