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,17 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface Cache
{
public const STATS_HITS = 'hits';
public const STATS_MISSES = 'misses';
public const STATS_UPTIME = 'uptime';
public const STATS_MEMORY_USAGE = 'memory_usage';
public const STATS_MEMORY_AVAILABLE = 'memory_available';
public const STATS_MEMORY_AVAILIABLE = 'memory_available';
public function fetch($id);
public function contains($id);
public function save($id, $data, $lifeTime = 0);
public function delete($id);
public function getStats();
}
@@ -0,0 +1,145 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
use function array_combine;
use function array_key_exists;
use function array_map;
use function sprintf;
abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiOperationCache
{
public const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
private $namespace = '';
private $namespaceVersion;
public function setNamespace($namespace)
{
$this->namespace = (string) $namespace;
$this->namespaceVersion = null;
}
public function getNamespace()
{
return $this->namespace;
}
public function fetch($id)
{
return $this->doFetch($this->getNamespacedId($id));
}
public function fetchMultiple(array $keys)
{
if (empty($keys)) {
return [];
}
// note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys
$namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys));
$items = $this->doFetchMultiple($namespacedKeys);
$foundItems = [];
// no internal array function supports this sort of mapping: needs to be iterative
// this filters and combines keys in one pass
foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
if (!isset($items[$namespacedKey]) && !array_key_exists($namespacedKey, $items)) {
continue;
}
$foundItems[$requestedKey] = $items[$namespacedKey];
}
return $foundItems;
}
public function saveMultiple(array $keysAndValues, $lifetime = 0)
{
$namespacedKeysAndValues = [];
foreach ($keysAndValues as $key => $value) {
$namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
}
return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
}
public function contains($id)
{
return $this->doContains($this->getNamespacedId($id));
}
public function save($id, $data, $lifeTime = 0)
{
return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
}
public function deleteMultiple(array $keys)
{
return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys));
}
public function delete($id)
{
return $this->doDelete($this->getNamespacedId($id));
}
public function getStats()
{
return $this->doGetStats();
}
public function flushAll()
{
return $this->doFlush();
}
public function deleteAll()
{
$namespaceCacheKey = $this->getNamespaceCacheKey();
$namespaceVersion = $this->getNamespaceVersion() + 1;
if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
$this->namespaceVersion = $namespaceVersion;
return \true;
}
return \false;
}
private function getNamespacedId(string $id) : string
{
$namespaceVersion = $this->getNamespaceVersion();
return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
}
private function getNamespaceCacheKey() : string
{
return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
}
private function getNamespaceVersion() : int
{
if ($this->namespaceVersion !== null) {
return $this->namespaceVersion;
}
$namespaceCacheKey = $this->getNamespaceCacheKey();
$this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1;
return $this->namespaceVersion;
}
protected function doFetchMultiple(array $keys)
{
$returnValues = [];
foreach ($keys as $key) {
$item = $this->doFetch($key);
if ($item === \false && !$this->doContains($key)) {
continue;
}
$returnValues[$key] = $item;
}
return $returnValues;
}
protected abstract function doFetch($id);
protected abstract function doContains($id);
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$success = \true;
foreach ($keysAndValues as $key => $value) {
if ($this->doSave($key, $value, $lifetime)) {
continue;
}
$success = \false;
}
return $success;
}
protected abstract function doSave($id, $data, $lifeTime = 0);
protected function doDeleteMultiple(array $keys)
{
$success = \true;
foreach ($keys as $key) {
if ($this->doDelete($key)) {
continue;
}
$success = \false;
}
return $success;
}
protected abstract function doDelete($id);
protected abstract function doFlush();
protected abstract function doGetStats();
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface ClearableCache
{
public function deleteAll();
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface FlushableCache
{
public function flushAll();
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface MultiDeleteCache
{
public function deleteMultiple(array $keys);
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface MultiGetCache
{
public function fetchMultiple(array $keys);
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface MultiOperationCache extends MultiGetCache, MultiDeleteCache, MultiPutCache
{
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache;
if (!defined('ABSPATH')) exit;
interface MultiPutCache
{
public function saveMultiple(array $keysAndValues, $lifetime = 0);
}
@@ -0,0 +1,237 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache\Psr6;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Cache\Cache;
use MailPoetVendor\Doctrine\Common\Cache\ClearableCache;
use MailPoetVendor\Doctrine\Common\Cache\MultiDeleteCache;
use MailPoetVendor\Doctrine\Common\Cache\MultiGetCache;
use MailPoetVendor\Doctrine\Common\Cache\MultiPutCache;
use MailPoetVendor\Psr\Cache\CacheItemInterface;
use MailPoetVendor\Psr\Cache\CacheItemPoolInterface;
use MailPoetVendor\Symfony\Component\Cache\DoctrineProvider as SymfonyDoctrineProvider;
use function array_key_exists;
use function assert;
use function count;
use function current;
use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function microtime;
use function sprintf;
use function strpbrk;
use const PHP_VERSION_ID;
final class CacheAdapter implements CacheItemPoolInterface
{
private const RESERVED_CHARACTERS = '{}()/\\@:';
private $cache;
private $deferredItems = [];
public static function wrap(Cache $cache) : CacheItemPoolInterface
{
if ($cache instanceof DoctrineProvider && !$cache->getNamespace()) {
return $cache->getPool();
}
if ($cache instanceof SymfonyDoctrineProvider && !$cache->getNamespace()) {
$getPool = function () {
// phpcs:ignore Squiz.Scope.StaticThisUsage.Found
return $this->pool;
};
return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)();
}
return new self($cache);
}
private function __construct(Cache $cache)
{
$this->cache = $cache;
}
public function getCache() : Cache
{
return $this->cache;
}
public function getItem($key) : CacheItemInterface
{
assert(self::validKey($key));
if (isset($this->deferredItems[$key])) {
$this->commit();
}
$value = $this->cache->fetch($key);
if (PHP_VERSION_ID >= 80000) {
if ($value !== \false) {
return new TypedCacheItem($key, $value, \true);
}
return new TypedCacheItem($key, null, \false);
}
if ($value !== \false) {
return new CacheItem($key, $value, \true);
}
return new CacheItem($key, null, \false);
}
public function getItems(array $keys = []) : array
{
if ($this->deferredItems) {
$this->commit();
}
assert(self::validKeys($keys));
$values = $this->doFetchMultiple($keys);
$items = [];
if (PHP_VERSION_ID >= 80000) {
foreach ($keys as $key) {
if (array_key_exists($key, $values)) {
$items[$key] = new TypedCacheItem($key, $values[$key], \true);
} else {
$items[$key] = new TypedCacheItem($key, null, \false);
}
}
return $items;
}
foreach ($keys as $key) {
if (array_key_exists($key, $values)) {
$items[$key] = new CacheItem($key, $values[$key], \true);
} else {
$items[$key] = new CacheItem($key, null, \false);
}
}
return $items;
}
public function hasItem($key) : bool
{
assert(self::validKey($key));
if (isset($this->deferredItems[$key])) {
$this->commit();
}
return $this->cache->contains($key);
}
public function clear() : bool
{
$this->deferredItems = [];
if (!$this->cache instanceof ClearableCache) {
return \false;
}
return $this->cache->deleteAll();
}
public function deleteItem($key) : bool
{
assert(self::validKey($key));
unset($this->deferredItems[$key]);
return $this->cache->delete($key);
}
public function deleteItems(array $keys) : bool
{
foreach ($keys as $key) {
assert(self::validKey($key));
unset($this->deferredItems[$key]);
}
return $this->doDeleteMultiple($keys);
}
public function save(CacheItemInterface $item) : bool
{
return $this->saveDeferred($item) && $this->commit();
}
public function saveDeferred(CacheItemInterface $item) : bool
{
if (!$item instanceof CacheItem && !$item instanceof TypedCacheItem) {
return \false;
}
$this->deferredItems[$item->getKey()] = $item;
return \true;
}
public function commit() : bool
{
if (!$this->deferredItems) {
return \true;
}
$now = microtime(\true);
$itemsCount = 0;
$byLifetime = [];
$expiredKeys = [];
foreach ($this->deferredItems as $key => $item) {
$lifetime = ($item->getExpiry() ?? $now) - $now;
if ($lifetime < 0) {
$expiredKeys[] = $key;
continue;
}
++$itemsCount;
$byLifetime[(int) $lifetime][$key] = $item->get();
}
$this->deferredItems = [];
switch (count($expiredKeys)) {
case 0:
break;
case 1:
$this->cache->delete(current($expiredKeys));
break;
default:
$this->doDeleteMultiple($expiredKeys);
break;
}
if ($itemsCount === 1) {
return $this->cache->save($key, $item->get(), (int) $lifetime);
}
$success = \true;
foreach ($byLifetime as $lifetime => $values) {
$success = $this->doSaveMultiple($values, $lifetime) && $success;
}
return $success;
}
public function __destruct()
{
$this->commit();
}
private static function validKey($key) : bool
{
if (!is_string($key)) {
throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
}
if ($key === '') {
throw new InvalidArgument('Cache key length must be greater than zero.');
}
if (strpbrk($key, self::RESERVED_CHARACTERS) !== \false) {
throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
}
return \true;
}
private static function validKeys(array $keys) : bool
{
foreach ($keys as $key) {
self::validKey($key);
}
return \true;
}
private function doDeleteMultiple(array $keys) : bool
{
if ($this->cache instanceof MultiDeleteCache) {
return $this->cache->deleteMultiple($keys);
}
$success = \true;
foreach ($keys as $key) {
$success = $this->cache->delete($key) && $success;
}
return $success;
}
private function doFetchMultiple(array $keys) : array
{
if ($this->cache instanceof MultiGetCache) {
return $this->cache->fetchMultiple($keys);
}
$values = [];
foreach ($keys as $key) {
$value = $this->cache->fetch($key);
if (!$value) {
continue;
}
$values[$key] = $value;
}
return $values;
}
private function doSaveMultiple(array $keysAndValues, int $lifetime = 0) : bool
{
if ($this->cache instanceof MultiPutCache) {
return $this->cache->saveMultiple($keysAndValues, $lifetime);
}
$success = \true;
foreach ($keysAndValues as $key => $value) {
$success = $this->cache->save($key, $value, $lifetime) && $success;
}
return $success;
}
}
@@ -0,0 +1,72 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache\Psr6;
if (!defined('ABSPATH')) exit;
use DateInterval;
use DateTime;
use DateTimeInterface;
use MailPoetVendor\Psr\Cache\CacheItemInterface;
use TypeError;
use function get_class;
use function gettype;
use function is_int;
use function is_object;
use function microtime;
use function sprintf;
final class CacheItem implements CacheItemInterface
{
private $key;
private $value;
private $isHit;
private $expiry;
public function __construct(string $key, $data, bool $isHit)
{
$this->key = $key;
$this->value = $data;
$this->isHit = $isHit;
}
public function getKey() : string
{
return $this->key;
}
public function get()
{
return $this->value;
}
public function isHit() : bool
{
return $this->isHit;
}
public function set($value) : self
{
$this->value = $value;
return $this;
}
public function expiresAt($expiration) : self
{
if ($expiration === null) {
$this->expiry = null;
} elseif ($expiration instanceof DateTimeInterface) {
$this->expiry = (float) $expiration->format('U.u');
} else {
throw new TypeError(sprintf('Expected $expiration to be an instance of DateTimeInterface or null, got %s', is_object($expiration) ? get_class($expiration) : gettype($expiration)));
}
return $this;
}
public function expiresAfter($time) : self
{
if ($time === null) {
$this->expiry = null;
} elseif ($time instanceof DateInterval) {
$this->expiry = microtime(\true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
} elseif (is_int($time)) {
$this->expiry = $time + microtime(\true);
} else {
throw new TypeError(sprintf('Expected $time to be either an integer, an instance of DateInterval or null, got %s', is_object($time) ? get_class($time) : gettype($time)));
}
return $this;
}
public function getExpiry() : ?float
{
return $this->expiry;
}
}
@@ -0,0 +1,71 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache\Psr6;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Cache\Cache;
use MailPoetVendor\Doctrine\Common\Cache\CacheProvider;
use MailPoetVendor\Psr\Cache\CacheItemPoolInterface;
use MailPoetVendor\Symfony\Component\Cache\Adapter\DoctrineAdapter as SymfonyDoctrineAdapter;
use MailPoetVendor\Symfony\Contracts\Service\ResetInterface;
use function rawurlencode;
final class DoctrineProvider extends CacheProvider
{
private $pool;
public static function wrap(CacheItemPoolInterface $pool) : Cache
{
if ($pool instanceof CacheAdapter) {
return $pool->getCache();
}
if ($pool instanceof SymfonyDoctrineAdapter) {
$getCache = function () {
// phpcs:ignore Squiz.Scope.StaticThisUsage.Found
return $this->provider;
};
return $getCache->bindTo($pool, SymfonyDoctrineAdapter::class)();
}
return new self($pool);
}
private function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
}
public function getPool() : CacheItemPoolInterface
{
return $this->pool;
}
public function reset() : void
{
if ($this->pool instanceof ResetInterface) {
$this->pool->reset();
}
$this->setNamespace($this->getNamespace());
}
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : \false;
}
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
protected function doSave($id, $data, $lifeTime = 0)
{
$item = $this->pool->getItem(rawurlencode($id));
if (0 < $lifeTime) {
$item->expiresAfter($lifeTime);
}
return $this->pool->save($item->set($data));
}
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
protected function doFlush()
{
return $this->pool->clear();
}
protected function doGetStats()
{
return null;
}
}
@@ -0,0 +1,8 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache\Psr6;
if (!defined('ABSPATH')) exit;
use InvalidArgumentException;
use MailPoetVendor\Psr\Cache\InvalidArgumentException as PsrInvalidArgumentException;
final class InvalidArgument extends InvalidArgumentException implements PsrInvalidArgumentException
{
}
@@ -0,0 +1,64 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Cache\Psr6;
if (!defined('ABSPATH')) exit;
use DateInterval;
use DateTime;
use DateTimeInterface;
use MailPoetVendor\Psr\Cache\CacheItemInterface;
use TypeError;
use function get_debug_type;
use function is_int;
use function microtime;
use function sprintf;
final class TypedCacheItem implements CacheItemInterface
{
private ?float $expiry = null;
public function __construct(private string $key, private mixed $value, private bool $isHit)
{
}
public function getKey() : string
{
return $this->key;
}
public function get() : mixed
{
return $this->value;
}
public function isHit() : bool
{
return $this->isHit;
}
public function set(mixed $value) : static
{
$this->value = $value;
return $this;
}
public function expiresAt($expiration) : static
{
if ($expiration === null) {
$this->expiry = null;
} elseif ($expiration instanceof DateTimeInterface) {
$this->expiry = (float) $expiration->format('U.u');
} else {
throw new TypeError(sprintf('Expected $expiration to be an instance of DateTimeInterface or null, got %s', get_debug_type($expiration)));
}
return $this;
}
public function expiresAfter($time) : static
{
if ($time === null) {
$this->expiry = null;
} elseif ($time instanceof DateInterval) {
$this->expiry = microtime(\true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
} elseif (is_int($time)) {
$this->expiry = $time + microtime(\true);
} else {
throw new TypeError(sprintf('Expected $time to be either an integer, an instance of DateInterval or null, got %s', get_debug_type($time)));
}
return $this;
}
public function getExpiry() : ?float
{
return $this->expiry;
}
}
@@ -0,0 +1 @@
<?php
@@ -0,0 +1 @@
<?php
@@ -0,0 +1,180 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
use Closure;
use ReturnTypeWillChange;
use Traversable;
abstract class AbstractLazyCollection implements Collection
{
protected $collection;
protected $initialized = \false;
#[\ReturnTypeWillChange]
public function count()
{
$this->initialize();
return $this->collection->count();
}
public function add($element)
{
$this->initialize();
return $this->collection->add($element);
}
public function clear()
{
$this->initialize();
$this->collection->clear();
}
public function contains($element)
{
$this->initialize();
return $this->collection->contains($element);
}
public function isEmpty()
{
$this->initialize();
return $this->collection->isEmpty();
}
public function remove($key)
{
$this->initialize();
return $this->collection->remove($key);
}
public function removeElement($element)
{
$this->initialize();
return $this->collection->removeElement($element);
}
public function containsKey($key)
{
$this->initialize();
return $this->collection->containsKey($key);
}
public function get($key)
{
$this->initialize();
return $this->collection->get($key);
}
public function getKeys()
{
$this->initialize();
return $this->collection->getKeys();
}
public function getValues()
{
$this->initialize();
return $this->collection->getValues();
}
public function set($key, $value)
{
$this->initialize();
$this->collection->set($key, $value);
}
public function toArray()
{
$this->initialize();
return $this->collection->toArray();
}
public function first()
{
$this->initialize();
return $this->collection->first();
}
public function last()
{
$this->initialize();
return $this->collection->last();
}
public function key()
{
$this->initialize();
return $this->collection->key();
}
public function current()
{
$this->initialize();
return $this->collection->current();
}
public function next()
{
$this->initialize();
return $this->collection->next();
}
public function exists(Closure $p)
{
$this->initialize();
return $this->collection->exists($p);
}
public function filter(Closure $p)
{
$this->initialize();
return $this->collection->filter($p);
}
public function forAll(Closure $p)
{
$this->initialize();
return $this->collection->forAll($p);
}
public function map(Closure $func)
{
$this->initialize();
return $this->collection->map($func);
}
public function partition(Closure $p)
{
$this->initialize();
return $this->collection->partition($p);
}
public function indexOf($element)
{
$this->initialize();
return $this->collection->indexOf($element);
}
public function slice($offset, $length = null)
{
$this->initialize();
return $this->collection->slice($offset, $length);
}
#[\ReturnTypeWillChange]
public function getIterator()
{
$this->initialize();
return $this->collection->getIterator();
}
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
$this->initialize();
return $this->collection->offsetExists($offset);
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
$this->initialize();
return $this->collection->offsetGet($offset);
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
$this->initialize();
$this->collection->offsetSet($offset, $value);
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->initialize();
$this->collection->offsetUnset($offset);
}
public function isInitialized()
{
return $this->initialized;
}
protected function initialize()
{
if ($this->initialized) {
return;
}
$this->doInitialize();
$this->initialized = \true;
}
protected abstract function doInitialize();
}
@@ -0,0 +1,225 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
use ArrayIterator;
use Closure;
use MailPoetVendor\Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
use ReturnTypeWillChange;
use Traversable;
use function array_filter;
use function array_key_exists;
use function array_keys;
use function array_map;
use function array_reverse;
use function array_search;
use function array_slice;
use function array_values;
use function count;
use function current;
use function end;
use function in_array;
use function key;
use function next;
use function reset;
use function spl_object_hash;
use function uasort;
use const ARRAY_FILTER_USE_BOTH;
class ArrayCollection implements Collection, Selectable
{
private $elements;
public function __construct(array $elements = [])
{
$this->elements = $elements;
}
public function toArray()
{
return $this->elements;
}
public function first()
{
return reset($this->elements);
}
protected function createFrom(array $elements)
{
return new static($elements);
}
public function last()
{
return end($this->elements);
}
public function key()
{
return key($this->elements);
}
public function next()
{
return next($this->elements);
}
public function current()
{
return current($this->elements);
}
public function remove($key)
{
if (!isset($this->elements[$key]) && !array_key_exists($key, $this->elements)) {
return null;
}
$removed = $this->elements[$key];
unset($this->elements[$key]);
return $removed;
}
public function removeElement($element)
{
$key = array_search($element, $this->elements, \true);
if ($key === \false) {
return \false;
}
unset($this->elements[$key]);
return \true;
}
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return $this->containsKey($offset);
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->get($offset);
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!isset($offset)) {
$this->add($value);
return;
}
$this->set($offset, $value);
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->remove($offset);
}
public function containsKey($key)
{
return isset($this->elements[$key]) || array_key_exists($key, $this->elements);
}
public function contains($element)
{
return in_array($element, $this->elements, \true);
}
public function exists(Closure $p)
{
foreach ($this->elements as $key => $element) {
if ($p($key, $element)) {
return \true;
}
}
return \false;
}
public function indexOf($element)
{
return array_search($element, $this->elements, \true);
}
public function get($key)
{
return $this->elements[$key] ?? null;
}
public function getKeys()
{
return array_keys($this->elements);
}
public function getValues()
{
return array_values($this->elements);
}
#[\ReturnTypeWillChange]
public function count()
{
return count($this->elements);
}
public function set($key, $value)
{
$this->elements[$key] = $value;
}
public function add($element)
{
$this->elements[] = $element;
return \true;
}
public function isEmpty()
{
return empty($this->elements);
}
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->elements);
}
public function map(Closure $func)
{
return $this->createFrom(array_map($func, $this->elements));
}
public function filter(Closure $p)
{
return $this->createFrom(array_filter($this->elements, $p, ARRAY_FILTER_USE_BOTH));
}
public function forAll(Closure $p)
{
foreach ($this->elements as $key => $element) {
if (!$p($key, $element)) {
return \false;
}
}
return \true;
}
public function partition(Closure $p)
{
$matches = $noMatches = [];
foreach ($this->elements as $key => $element) {
if ($p($key, $element)) {
$matches[$key] = $element;
} else {
$noMatches[$key] = $element;
}
}
return [$this->createFrom($matches), $this->createFrom($noMatches)];
}
public function __toString()
{
return self::class . '@' . spl_object_hash($this);
}
public function clear()
{
$this->elements = [];
}
public function slice($offset, $length = null)
{
return array_slice($this->elements, $offset, $length, \true);
}
public function matching(Criteria $criteria)
{
$expr = $criteria->getWhereExpression();
$filtered = $this->elements;
if ($expr) {
$visitor = new ClosureExpressionVisitor();
$filter = $visitor->dispatch($expr);
$filtered = array_filter($filtered, $filter);
}
$orderings = $criteria->getOrderings();
if ($orderings) {
$next = null;
foreach (array_reverse($orderings) as $field => $ordering) {
$next = ClosureExpressionVisitor::sortByField($field, $ordering === Criteria::DESC ? -1 : 1, $next);
}
uasort($filtered, $next);
}
$offset = $criteria->getFirstResult();
$length = $criteria->getMaxResults();
if ($offset || $length) {
$filtered = array_slice($filtered, (int) $offset, $length);
}
return $this->createFrom($filtered);
}
}
@@ -0,0 +1,34 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
use ArrayAccess;
use Closure;
use Countable;
use IteratorAggregate;
interface Collection extends Countable, IteratorAggregate, ArrayAccess
{
public function add($element);
public function clear();
public function contains($element);
public function isEmpty();
public function remove($key);
public function removeElement($element);
public function containsKey($key);
public function get($key);
public function getKeys();
public function getValues();
public function set($key, $value);
public function toArray();
public function first();
public function last();
public function key();
public function current();
public function next();
public function exists(Closure $p);
public function filter(Closure $p);
public function forAll(Closure $p);
public function map(Closure $func);
public function partition(Closure $p);
public function indexOf($element);
public function slice($offset, $length = null);
}
@@ -0,0 +1,92 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Collections\Expr\CompositeExpression;
use MailPoetVendor\Doctrine\Common\Collections\Expr\Expression;
use function array_map;
use function strtoupper;
class Criteria
{
public const ASC = 'ASC';
public const DESC = 'DESC';
private static $expressionBuilder;
private $expression;
private $orderings = [];
private $firstResult;
private $maxResults;
public static function create()
{
return new static();
}
public static function expr()
{
if (self::$expressionBuilder === null) {
self::$expressionBuilder = new ExpressionBuilder();
}
return self::$expressionBuilder;
}
public function __construct(?Expression $expression = null, ?array $orderings = null, $firstResult = null, $maxResults = null)
{
$this->expression = $expression;
$this->setFirstResult($firstResult);
$this->setMaxResults($maxResults);
if ($orderings === null) {
return;
}
$this->orderBy($orderings);
}
public function where(Expression $expression)
{
$this->expression = $expression;
return $this;
}
public function andWhere(Expression $expression)
{
if ($this->expression === null) {
return $this->where($expression);
}
$this->expression = new CompositeExpression(CompositeExpression::TYPE_AND, [$this->expression, $expression]);
return $this;
}
public function orWhere(Expression $expression)
{
if ($this->expression === null) {
return $this->where($expression);
}
$this->expression = new CompositeExpression(CompositeExpression::TYPE_OR, [$this->expression, $expression]);
return $this;
}
public function getWhereExpression()
{
return $this->expression;
}
public function getOrderings()
{
return $this->orderings;
}
public function orderBy(array $orderings)
{
$this->orderings = array_map(static function (string $ordering) : string {
return strtoupper($ordering) === Criteria::ASC ? Criteria::ASC : Criteria::DESC;
}, $orderings);
return $this;
}
public function getFirstResult()
{
return $this->firstResult;
}
public function setFirstResult($firstResult)
{
$this->firstResult = $firstResult;
return $this;
}
public function getMaxResults()
{
return $this->maxResults;
}
public function setMaxResults($maxResults)
{
$this->maxResults = $maxResults;
return $this;
}
}
@@ -0,0 +1,179 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
use ArrayAccess;
use Closure;
use RuntimeException;
use function in_array;
use function is_array;
use function is_scalar;
use function iterator_to_array;
use function method_exists;
use function preg_match;
use function preg_replace_callback;
use function strlen;
use function strpos;
use function strtoupper;
use function substr;
class ClosureExpressionVisitor extends ExpressionVisitor
{
public static function getObjectFieldValue($object, $field)
{
if (is_array($object)) {
return $object[$field];
}
$accessors = ['get', 'is'];
foreach ($accessors as $accessor) {
$accessor .= $field;
if (method_exists($object, $accessor)) {
return $object->{$accessor}();
}
}
if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) {
return $object->{$field}();
}
// __call should be triggered for get.
$accessor = $accessors[0] . $field;
if (method_exists($object, '__call')) {
return $object->{$accessor}();
}
if ($object instanceof ArrayAccess) {
return $object[$field];
}
if (isset($object->{$field})) {
return $object->{$field};
}
// camelcase field name to support different variable naming conventions
$ccField = preg_replace_callback('/_(.?)/', static function ($matches) {
return strtoupper($matches[1]);
}, $field);
foreach ($accessors as $accessor) {
$accessor .= $ccField;
if (method_exists($object, $accessor)) {
return $object->{$accessor}();
}
}
return $object->{$field};
}
public static function sortByField($name, $orientation = 1, ?Closure $next = null)
{
if (!$next) {
$next = static function () : int {
return 0;
};
}
return static function ($a, $b) use($name, $next, $orientation) : int {
$aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
$bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
if ($aValue === $bValue) {
return $next($a, $b);
}
return ($aValue > $bValue ? 1 : -1) * $orientation;
};
}
public function walkComparison(Comparison $comparison)
{
$field = $comparison->getField();
$value = $comparison->getValue()->getValue();
// shortcut for walkValue()
switch ($comparison->getOperator()) {
case Comparison::EQ:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
};
case Comparison::NEQ:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
};
case Comparison::LT:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
};
case Comparison::LTE:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
};
case Comparison::GT:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
};
case Comparison::GTE:
return static function ($object) use($field, $value) : bool {
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
};
case Comparison::IN:
return static function ($object) use($field, $value) : bool {
$fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
return in_array($fieldValue, $value, is_scalar($fieldValue));
};
case Comparison::NIN:
return static function ($object) use($field, $value) : bool {
$fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
return !in_array($fieldValue, $value, is_scalar($fieldValue));
};
case Comparison::CONTAINS:
return static function ($object) use($field, $value) {
return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== \false;
};
case Comparison::MEMBER_OF:
return static function ($object) use($field, $value) : bool {
$fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field);
if (!is_array($fieldValues)) {
$fieldValues = iterator_to_array($fieldValues);
}
return in_array($value, $fieldValues, \true);
};
case Comparison::STARTS_WITH:
return static function ($object) use($field, $value) : bool {
return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0;
};
case Comparison::ENDS_WITH:
return static function ($object) use($field, $value) : bool {
return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value));
};
default:
throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
}
}
public function walkValue(Value $value)
{
return $value->getValue();
}
public function walkCompositeExpression(CompositeExpression $expr)
{
$expressionList = [];
foreach ($expr->getExpressionList() as $child) {
$expressionList[] = $this->dispatch($child);
}
switch ($expr->getType()) {
case CompositeExpression::TYPE_AND:
return $this->andExpressions($expressionList);
case CompositeExpression::TYPE_OR:
return $this->orExpressions($expressionList);
default:
throw new RuntimeException('Unknown composite ' . $expr->getType());
}
}
private function andExpressions(array $expressions) : callable
{
return static function ($object) use($expressions) : bool {
foreach ($expressions as $expression) {
if (!$expression($object)) {
return \false;
}
}
return \true;
};
}
private function orExpressions(array $expressions) : callable
{
return static function ($object) use($expressions) : bool {
foreach ($expressions as $expression) {
if ($expression($object)) {
return \true;
}
}
return \false;
};
}
}
@@ -0,0 +1,48 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
class Comparison implements Expression
{
public const EQ = '=';
public const NEQ = '<>';
public const LT = '<';
public const LTE = '<=';
public const GT = '>';
public const GTE = '>=';
public const IS = '=';
// no difference with EQ
public const IN = 'IN';
public const NIN = 'NIN';
public const CONTAINS = 'CONTAINS';
public const MEMBER_OF = 'MEMBER_OF';
public const STARTS_WITH = 'STARTS_WITH';
public const ENDS_WITH = 'ENDS_WITH';
private $field;
private $op;
private $value;
public function __construct($field, $operator, $value)
{
if (!$value instanceof Value) {
$value = new Value($value);
}
$this->field = $field;
$this->op = $operator;
$this->value = $value;
}
public function getField()
{
return $this->field;
}
public function getValue()
{
return $this->value;
}
public function getOperator()
{
return $this->op;
}
public function visit(ExpressionVisitor $visitor)
{
return $visitor->walkComparison($this);
}
}
@@ -0,0 +1,36 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
use RuntimeException;
class CompositeExpression implements Expression
{
public const TYPE_AND = 'AND';
public const TYPE_OR = 'OR';
private $type;
private $expressions = [];
public function __construct($type, array $expressions)
{
$this->type = $type;
foreach ($expressions as $expr) {
if ($expr instanceof Value) {
throw new RuntimeException('Values are not supported expressions as children of and/or expressions.');
}
if (!$expr instanceof Expression) {
throw new RuntimeException('No expression given to CompositeExpression.');
}
$this->expressions[] = $expr;
}
}
public function getExpressionList()
{
return $this->expressions;
}
public function getType()
{
return $this->type;
}
public function visit(ExpressionVisitor $visitor)
{
return $visitor->walkCompositeExpression($this);
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
interface Expression
{
public function visit(ExpressionVisitor $visitor);
}
@@ -0,0 +1,24 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
use RuntimeException;
use function get_class;
abstract class ExpressionVisitor
{
public abstract function walkComparison(Comparison $comparison);
public abstract function walkValue(Value $value);
public abstract function walkCompositeExpression(CompositeExpression $expr);
public function dispatch(Expression $expr)
{
switch (\true) {
case $expr instanceof Comparison:
return $this->walkComparison($expr);
case $expr instanceof Value:
return $this->walkValue($expr);
case $expr instanceof CompositeExpression:
return $this->walkCompositeExpression($expr);
default:
throw new RuntimeException('Unknown Expression ' . get_class($expr));
}
}
}
@@ -0,0 +1,19 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections\Expr;
if (!defined('ABSPATH')) exit;
class Value implements Expression
{
private $value;
public function __construct($value)
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
public function visit(ExpressionVisitor $visitor)
{
return $visitor->walkValue($this);
}
}
@@ -0,0 +1,70 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Collections\Expr\Comparison;
use MailPoetVendor\Doctrine\Common\Collections\Expr\CompositeExpression;
use MailPoetVendor\Doctrine\Common\Collections\Expr\Value;
use function func_get_args;
class ExpressionBuilder
{
public function andX($x = null)
{
return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args());
}
public function orX($x = null)
{
return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args());
}
public function eq($field, $value)
{
return new Comparison($field, Comparison::EQ, new Value($value));
}
public function gt($field, $value)
{
return new Comparison($field, Comparison::GT, new Value($value));
}
public function lt($field, $value)
{
return new Comparison($field, Comparison::LT, new Value($value));
}
public function gte($field, $value)
{
return new Comparison($field, Comparison::GTE, new Value($value));
}
public function lte($field, $value)
{
return new Comparison($field, Comparison::LTE, new Value($value));
}
public function neq($field, $value)
{
return new Comparison($field, Comparison::NEQ, new Value($value));
}
public function isNull($field)
{
return new Comparison($field, Comparison::EQ, new Value(null));
}
public function in($field, array $values)
{
return new Comparison($field, Comparison::IN, new Value($values));
}
public function notIn($field, array $values)
{
return new Comparison($field, Comparison::NIN, new Value($values));
}
public function contains($field, $value)
{
return new Comparison($field, Comparison::CONTAINS, new Value($value));
}
public function memberOf($field, $value)
{
return new Comparison($field, Comparison::MEMBER_OF, new Value($value));
}
public function startsWith($field, $value)
{
return new Comparison($field, Comparison::STARTS_WITH, new Value($value));
}
public function endsWith($field, $value)
{
return new Comparison($field, Comparison::ENDS_WITH, new Value($value));
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\Common\Collections;
if (!defined('ABSPATH')) exit;
interface Selectable
{
public function matching(Criteria $criteria);
}
@@ -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);
}
}
@@ -0,0 +1 @@
<?php
@@ -0,0 +1,17 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
final class ArrayParameterType
{
public const INTEGER = ParameterType::INTEGER + Connection::ARRAY_PARAM_OFFSET;
public const STRING = ParameterType::STRING + Connection::ARRAY_PARAM_OFFSET;
public const ASCII = ParameterType::ASCII + Connection::ARRAY_PARAM_OFFSET;
public const BINARY = ParameterType::BINARY + Connection::ARRAY_PARAM_OFFSET;
public static function toElementParameterType(int $type) : int
{
return $type - Connection::ARRAY_PARAM_OFFSET;
}
private function __construct()
{
}
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\ArrayParameters;
if (!defined('ABSPATH')) exit;
use Throwable;
interface Exception extends Throwable
{
}
@@ -0,0 +1,13 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\ArrayParameters\Exception;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\ArrayParameters\Exception;
use LogicException;
use function sprintf;
class MissingNamedParameter extends LogicException implements Exception
{
public static function new(string $name) : self
{
return new self(sprintf('Named parameter "%s" does not have a bound value.', $name));
}
}
@@ -0,0 +1,13 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\ArrayParameters\Exception;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\ArrayParameters\Exception;
use LogicException;
use function sprintf;
class MissingPositionalParameter extends LogicException implements Exception
{
public static function new(int $index) : self
{
return new self(sprintf('Positional parameter at index %d does not have a bound value.', $index));
}
}
@@ -0,0 +1,73 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Cache;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\FetchUtils;
use MailPoetVendor\Doctrine\DBAL\Driver\Result;
use function array_values;
use function count;
use function reset;
final class ArrayResult implements Result
{
private array $data;
private int $columnCount = 0;
private int $num = 0;
public function __construct(array $data)
{
$this->data = $data;
if (count($data) === 0) {
return;
}
$this->columnCount = count($data[0]);
}
public function fetchNumeric()
{
$row = $this->fetch();
if ($row === \false) {
return \false;
}
return array_values($row);
}
public function fetchAssociative()
{
return $this->fetch();
}
public function fetchOne()
{
$row = $this->fetch();
if ($row === \false) {
return \false;
}
return reset($row);
}
public function fetchAllNumeric() : array
{
return FetchUtils::fetchAllNumeric($this);
}
public function fetchAllAssociative() : array
{
return FetchUtils::fetchAllAssociative($this);
}
public function fetchFirstColumn() : array
{
return FetchUtils::fetchFirstColumn($this);
}
public function rowCount() : int
{
return count($this->data);
}
public function columnCount() : int
{
return $this->columnCount;
}
public function free() : void
{
$this->data = [];
}
private function fetch()
{
if (!isset($this->data[$this->num])) {
return \false;
}
return $this->data[$this->num++];
}
}
@@ -0,0 +1,15 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Cache;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Exception;
class CacheException extends Exception
{
public static function noCacheKey()
{
return new self('No cache key was set.');
}
public static function noResultDriverConfigured()
{
return new self('Trying to cache a query but no result driver is configured.');
}
}
@@ -0,0 +1,81 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Cache;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Cache\Cache;
use MailPoetVendor\Doctrine\Common\Cache\Psr6\CacheAdapter;
use MailPoetVendor\Doctrine\Common\Cache\Psr6\DoctrineProvider;
use MailPoetVendor\Doctrine\DBAL\Types\Type;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use MailPoetVendor\Psr\Cache\CacheItemPoolInterface;
use TypeError;
use function get_class;
use function hash;
use function serialize;
use function sha1;
use function sprintf;
class QueryCacheProfile
{
private ?CacheItemPoolInterface $resultCache = null;
private $lifetime;
private $cacheKey;
public function __construct($lifetime = 0, $cacheKey = null, ?object $resultCache = null)
{
$this->lifetime = $lifetime;
$this->cacheKey = $cacheKey;
if ($resultCache instanceof CacheItemPoolInterface) {
$this->resultCache = $resultCache;
} elseif ($resultCache instanceof Cache) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4620', 'Passing an instance of %s to %s as $resultCache is deprecated. Pass an instance of %s instead.', Cache::class, __METHOD__, CacheItemPoolInterface::class);
$this->resultCache = CacheAdapter::wrap($resultCache);
} elseif ($resultCache !== null) {
throw new TypeError(sprintf('$resultCache: Expected either null or an instance of %s or %s, got %s.', CacheItemPoolInterface::class, Cache::class, get_class($resultCache)));
}
}
public function getResultCache() : ?CacheItemPoolInterface
{
return $this->resultCache;
}
public function getResultCacheDriver()
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4620', '%s is deprecated, call getResultCache() instead.', __METHOD__);
return $this->resultCache !== null ? DoctrineProvider::wrap($this->resultCache) : null;
}
public function getLifetime()
{
return $this->lifetime;
}
public function getCacheKey()
{
if ($this->cacheKey === null) {
throw CacheException::noCacheKey();
}
return $this->cacheKey;
}
public function generateCacheKeys($sql, $params, $types, array $connectionParams = [])
{
if (isset($connectionParams['password'])) {
unset($connectionParams['password']);
}
$realCacheKey = 'query=' . $sql . '&params=' . serialize($params) . '&types=' . serialize($types) . '&connectionParams=' . hash('sha256', serialize($connectionParams));
// should the key be automatically generated using the inputs or is the cache key set?
$cacheKey = $this->cacheKey ?? sha1($realCacheKey);
return [$cacheKey, $realCacheKey];
}
public function setResultCache(CacheItemPoolInterface $cache) : QueryCacheProfile
{
return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache);
}
public function setResultCacheDriver(Cache $cache)
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4620', '%s is deprecated, call setResultCache() instead.', __METHOD__);
return new QueryCacheProfile($this->lifetime, $this->cacheKey, CacheAdapter::wrap($cache));
}
public function setCacheKey($cacheKey)
{
return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCache);
}
public function setLifetime($lifetime)
{
return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCache);
}
}
@@ -0,0 +1,11 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
final class ColumnCase
{
public const UPPER = 1;
public const LOWER = 2;
private function __construct()
{
}
}
@@ -0,0 +1,107 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\Cache\Cache;
use MailPoetVendor\Doctrine\Common\Cache\Psr6\CacheAdapter;
use MailPoetVendor\Doctrine\Common\Cache\Psr6\DoctrineProvider;
use MailPoetVendor\Doctrine\DBAL\Driver\Middleware;
use MailPoetVendor\Doctrine\DBAL\Logging\SQLLogger;
use MailPoetVendor\Doctrine\DBAL\Schema\SchemaManagerFactory;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use MailPoetVendor\Psr\Cache\CacheItemPoolInterface;
use function func_num_args;
class Configuration
{
private array $middlewares = [];
protected $sqlLogger;
private ?CacheItemPoolInterface $resultCache = null;
protected $resultCacheImpl;
protected $schemaAssetsFilter;
protected $autoCommit = \true;
private bool $disableTypeComments = \false;
private ?SchemaManagerFactory $schemaManagerFactory = null;
public function __construct()
{
$this->schemaAssetsFilter = static function () : bool {
return \true;
};
}
public function setSQLLogger(?SQLLogger $logger = null) : void
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4967', '%s is deprecated, use setMiddlewares() and Logging\\Middleware instead.', __METHOD__);
$this->sqlLogger = $logger;
}
public function getSQLLogger() : ?SQLLogger
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4967', '%s is deprecated.', __METHOD__);
return $this->sqlLogger;
}
public function getResultCache() : ?CacheItemPoolInterface
{
return $this->resultCache;
}
public function getResultCacheImpl() : ?Cache
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4620', '%s is deprecated, call getResultCache() instead.', __METHOD__);
return $this->resultCacheImpl;
}
public function setResultCache(CacheItemPoolInterface $cache) : void
{
$this->resultCacheImpl = DoctrineProvider::wrap($cache);
$this->resultCache = $cache;
}
public function setResultCacheImpl(Cache $cacheImpl) : void
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4620', '%s is deprecated, call setResultCache() instead.', __METHOD__);
$this->resultCacheImpl = $cacheImpl;
$this->resultCache = CacheAdapter::wrap($cacheImpl);
}
public function setSchemaAssetsFilter(?callable $callable = null) : void
{
if (func_num_args() < 1) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5483', 'Not passing an argument to %s is deprecated.', __METHOD__);
} elseif ($callable === null) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5483', 'Using NULL as a schema asset filter is deprecated.' . ' Use a callable that always returns true instead.');
}
$this->schemaAssetsFilter = $callable;
}
public function getSchemaAssetsFilter() : ?callable
{
return $this->schemaAssetsFilter;
}
public function setAutoCommit(bool $autoCommit) : void
{
$this->autoCommit = $autoCommit;
}
public function getAutoCommit() : bool
{
return $this->autoCommit;
}
public function setMiddlewares(array $middlewares) : self
{
$this->middlewares = $middlewares;
return $this;
}
public function getMiddlewares() : array
{
return $this->middlewares;
}
public function getSchemaManagerFactory() : ?SchemaManagerFactory
{
return $this->schemaManagerFactory;
}
public function setSchemaManagerFactory(SchemaManagerFactory $schemaManagerFactory) : self
{
$this->schemaManagerFactory = $schemaManagerFactory;
return $this;
}
public function getDisableTypeComments() : bool
{
return $this->disableTypeComments;
}
public function setDisableTypeComments(bool $disableTypeComments) : self
{
$this->disableTypeComments = $disableTypeComments;
return $this;
}
}
@@ -0,0 +1,842 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
use Closure;
use MailPoetVendor\Doctrine\Common\EventManager;
use MailPoetVendor\Doctrine\DBAL\Cache\ArrayResult;
use MailPoetVendor\Doctrine\DBAL\Cache\CacheException;
use MailPoetVendor\Doctrine\DBAL\Cache\QueryCacheProfile;
use MailPoetVendor\Doctrine\DBAL\Driver\API\ExceptionConverter;
use MailPoetVendor\Doctrine\DBAL\Driver\Connection as DriverConnection;
use MailPoetVendor\Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use MailPoetVendor\Doctrine\DBAL\Driver\Statement as DriverStatement;
use MailPoetVendor\Doctrine\DBAL\Event\TransactionBeginEventArgs;
use MailPoetVendor\Doctrine\DBAL\Event\TransactionCommitEventArgs;
use MailPoetVendor\Doctrine\DBAL\Event\TransactionRollBackEventArgs;
use MailPoetVendor\Doctrine\DBAL\Exception\ConnectionLost;
use MailPoetVendor\Doctrine\DBAL\Exception\DriverException;
use MailPoetVendor\Doctrine\DBAL\Exception\InvalidArgumentException;
use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractPlatform;
use MailPoetVendor\Doctrine\DBAL\Query\Expression\ExpressionBuilder;
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
use MailPoetVendor\Doctrine\DBAL\Schema\AbstractSchemaManager;
use MailPoetVendor\Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use MailPoetVendor\Doctrine\DBAL\Schema\LegacySchemaManagerFactory;
use MailPoetVendor\Doctrine\DBAL\Schema\SchemaManagerFactory;
use MailPoetVendor\Doctrine\DBAL\SQL\Parser;
use MailPoetVendor\Doctrine\DBAL\Types\Type;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use LogicException;
use MailPoetVendor\SensitiveParameter;
use Throwable;
use Traversable;
use function array_key_exists;
use function assert;
use function count;
use function get_class;
use function implode;
use function is_array;
use function is_int;
use function is_string;
use function key;
use function method_exists;
use function sprintf;
class Connection
{
public const PARAM_INT_ARRAY = ArrayParameterType::INTEGER;
public const PARAM_STR_ARRAY = ArrayParameterType::STRING;
public const PARAM_ASCII_STR_ARRAY = ArrayParameterType::ASCII;
public const ARRAY_PARAM_OFFSET = 100;
protected $_conn;
protected $_config;
protected $_eventManager;
protected $_expr;
private bool $autoCommit = \true;
private int $transactionNestingLevel = 0;
private $transactionIsolationLevel;
private bool $nestTransactionsWithSavepoints = \false;
private array $params;
private ?AbstractPlatform $platform = null;
private ?ExceptionConverter $exceptionConverter = null;
private ?Parser $parser = null;
protected $_schemaManager;
protected $_driver;
private bool $isRollbackOnly = \false;
private SchemaManagerFactory $schemaManagerFactory;
public function __construct( array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null)
{
$this->_driver = $driver;
$this->params = $params;
// Create default config and event manager if none given
$config ??= new Configuration();
$eventManager ??= new EventManager();
$this->_config = $config;
$this->_eventManager = $eventManager;
if (isset($params['platform'])) {
if (!$params['platform'] instanceof Platforms\AbstractPlatform) {
throw Exception::invalidPlatformType($params['platform']);
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5699', 'The "platform" connection parameter is deprecated.' . ' Use a driver middleware that would instantiate the platform instead.');
$this->platform = $params['platform'];
$this->platform->setEventManager($this->_eventManager);
$this->platform->setDisableTypeComments($config->getDisableTypeComments());
}
$this->_expr = $this->createExpressionBuilder();
$this->autoCommit = $config->getAutoCommit();
$schemaManagerFactory = $config->getSchemaManagerFactory();
if ($schemaManagerFactory === null) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5812', 'Not configuring a schema manager factory is deprecated.' . ' Use %s which is going to be the default in DBAL 4.', DefaultSchemaManagerFactory::class);
$schemaManagerFactory = new LegacySchemaManagerFactory();
}
$this->schemaManagerFactory = $schemaManagerFactory;
}
public function getParams()
{
return $this->params;
}
public function getDatabase()
{
$platform = $this->getDatabasePlatform();
$query = $platform->getDummySelectSQL($platform->getCurrentDatabaseExpression());
$database = $this->fetchOne($query);
assert(is_string($database) || $database === null);
return $database;
}
public function getDriver()
{
return $this->_driver;
}
public function getConfiguration()
{
return $this->_config;
}
public function getEventManager()
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5784', '%s is deprecated.', __METHOD__);
return $this->_eventManager;
}
public function getDatabasePlatform()
{
if ($this->platform === null) {
$this->platform = $this->detectDatabasePlatform();
$this->platform->setEventManager($this->_eventManager);
$this->platform->setDisableTypeComments($this->_config->getDisableTypeComments());
}
return $this->platform;
}
public function createExpressionBuilder() : ExpressionBuilder
{
return new ExpressionBuilder($this);
}
public function getExpressionBuilder()
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4515', 'Connection::getExpressionBuilder() is deprecated,' . ' use Connection::createExpressionBuilder() instead.');
return $this->_expr;
}
public function connect()
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4966', 'Public access to Connection::connect() is deprecated.');
if ($this->_conn !== null) {
return \false;
}
try {
$this->_conn = $this->_driver->connect($this->params);
} catch (Driver\Exception $e) {
throw $this->convertException($e);
}
if ($this->autoCommit === \false) {
$this->beginTransaction();
}
if ($this->_eventManager->hasListeners(Events::postConnect)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5784', 'Subscribing to %s events is deprecated. Implement a middleware instead.', Events::postConnect);
$eventArgs = new Event\ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
return \true;
}
private function detectDatabasePlatform() : AbstractPlatform
{
$version = $this->getDatabasePlatformVersion();
if ($version !== null) {
assert($this->_driver instanceof VersionAwarePlatformDriver);
return $this->_driver->createDatabasePlatformForVersion($version);
}
return $this->_driver->getDatabasePlatform();
}
private function getDatabasePlatformVersion()
{
// Driver does not support version specific platforms.
if (!$this->_driver instanceof VersionAwarePlatformDriver) {
return null;
}
// Explicit platform version requested (supersedes auto-detection).
if (isset($this->params['serverVersion'])) {
return $this->params['serverVersion'];
}
if (isset($this->params['primary']) && isset($this->params['primary']['serverVersion'])) {
return $this->params['primary']['serverVersion'];
}
// If not connected, we need to connect now to determine the platform version.
if ($this->_conn === null) {
try {
$this->connect();
} catch (Exception $originalException) {
if (!isset($this->params['dbname'])) {
throw $originalException;
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5707', 'Relying on a fallback connection used to determine the database platform while connecting' . ' to a non-existing database is deprecated. Either use an existing database name in' . ' connection parameters or omit the database name if the platform' . ' and the server configuration allow that.');
// The database to connect to might not yet exist.
// Retry detection without database name connection parameter.
$params = $this->params;
unset($this->params['dbname']);
try {
$this->connect();
} catch (Exception $fallbackException) {
// Either the platform does not support database-less connections
// or something else went wrong.
throw $originalException;
} finally {
$this->params = $params;
}
$serverVersion = $this->getServerVersion();
// Close "temporary" connection to allow connecting to the real database again.
$this->close();
return $serverVersion;
}
}
return $this->getServerVersion();
}
private function getServerVersion()
{
$connection = $this->getWrappedConnection();
// Automatic platform version detection.
if ($connection instanceof ServerInfoAwareConnection) {
try {
return $connection->getServerVersion();
} catch (Driver\Exception $e) {
throw $this->convertException($e);
}
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4750', 'Not implementing the ServerInfoAwareConnection interface in %s is deprecated', get_class($connection));
// Unable to detect platform version.
return null;
}
public function isAutoCommit()
{
return $this->autoCommit === \true;
}
public function setAutoCommit($autoCommit)
{
$autoCommit = (bool) $autoCommit;
// Mode not changed, no-op.
if ($autoCommit === $this->autoCommit) {
return;
}
$this->autoCommit = $autoCommit;
// Commit all currently active transactions if any when switching auto-commit mode.
if ($this->_conn === null || $this->transactionNestingLevel === 0) {
return;
}
$this->commitAll();
}
public function fetchAssociative(string $query, array $params = [], array $types = [])
{
return $this->executeQuery($query, $params, $types)->fetchAssociative();
}
public function fetchNumeric(string $query, array $params = [], array $types = [])
{
return $this->executeQuery($query, $params, $types)->fetchNumeric();
}
public function fetchOne(string $query, array $params = [], array $types = [])
{
return $this->executeQuery($query, $params, $types)->fetchOne();
}
public function isConnected()
{
return $this->_conn !== null;
}
public function isTransactionActive()
{
return $this->transactionNestingLevel > 0;
}
private function addCriteriaCondition(array $criteria, array &$columns, array &$values, array &$conditions) : void
{
$platform = $this->getDatabasePlatform();
foreach ($criteria as $columnName => $value) {
if ($value === null) {
$conditions[] = $platform->getIsNullExpression($columnName);
continue;
}
$columns[] = $columnName;
$values[] = $value;
$conditions[] = $columnName . ' = ?';
}
}
public function delete($table, array $criteria, array $types = [])
{
if (count($criteria) === 0) {
throw InvalidArgumentException::fromEmptyCriteria();
}
$columns = $values = $conditions = [];
$this->addCriteriaCondition($criteria, $columns, $values, $conditions);
return $this->executeStatement('DELETE FROM ' . $table . ' WHERE ' . implode(' AND ', $conditions), $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types);
}
public function close()
{
$this->_conn = null;
$this->transactionNestingLevel = 0;
}
public function setTransactionIsolation($level)
{
$this->transactionIsolationLevel = $level;
return $this->executeStatement($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level));
}
public function getTransactionIsolation()
{
return $this->transactionIsolationLevel ??= $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel();
}
public function update($table, array $data, array $criteria, array $types = [])
{
$columns = $values = $conditions = $set = [];
foreach ($data as $columnName => $value) {
$columns[] = $columnName;
$values[] = $value;
$set[] = $columnName . ' = ?';
}
$this->addCriteriaCondition($criteria, $columns, $values, $conditions);
if (is_string(key($types))) {
$types = $this->extractTypeValues($columns, $types);
}
$sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $set) . ' WHERE ' . implode(' AND ', $conditions);
return $this->executeStatement($sql, $values, $types);
}
public function insert($table, array $data, array $types = [])
{
if (count($data) === 0) {
return $this->executeStatement('INSERT INTO ' . $table . ' () VALUES ()');
}
$columns = [];
$values = [];
$set = [];
foreach ($data as $columnName => $value) {
$columns[] = $columnName;
$values[] = $value;
$set[] = '?';
}
return $this->executeStatement('INSERT INTO ' . $table . ' (' . implode(', ', $columns) . ')' . ' VALUES (' . implode(', ', $set) . ')', $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types);
}
private function extractTypeValues(array $columnList, array $types) : array
{
$typeValues = [];
foreach ($columnList as $columnName) {
$typeValues[] = $types[$columnName] ?? ParameterType::STRING;
}
return $typeValues;
}
public function quoteIdentifier($str)
{
return $this->getDatabasePlatform()->quoteIdentifier($str);
}
public function quote($value, $type = ParameterType::STRING)
{
$connection = $this->getWrappedConnection();
[$value, $bindingType] = $this->getBindingInfo($value, $type);
return $connection->quote($value, $bindingType);
}
public function fetchAllNumeric(string $query, array $params = [], array $types = []) : array
{
return $this->executeQuery($query, $params, $types)->fetchAllNumeric();
}
public function fetchAllAssociative(string $query, array $params = [], array $types = []) : array
{
return $this->executeQuery($query, $params, $types)->fetchAllAssociative();
}
public function fetchAllKeyValue(string $query, array $params = [], array $types = []) : array
{
return $this->executeQuery($query, $params, $types)->fetchAllKeyValue();
}
public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []) : array
{
return $this->executeQuery($query, $params, $types)->fetchAllAssociativeIndexed();
}
public function fetchFirstColumn(string $query, array $params = [], array $types = []) : array
{
return $this->executeQuery($query, $params, $types)->fetchFirstColumn();
}
public function iterateNumeric(string $query, array $params = [], array $types = []) : Traversable
{
return $this->executeQuery($query, $params, $types)->iterateNumeric();
}
public function iterateAssociative(string $query, array $params = [], array $types = []) : Traversable
{
return $this->executeQuery($query, $params, $types)->iterateAssociative();
}
public function iterateKeyValue(string $query, array $params = [], array $types = []) : Traversable
{
return $this->executeQuery($query, $params, $types)->iterateKeyValue();
}
public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []) : Traversable
{
return $this->executeQuery($query, $params, $types)->iterateAssociativeIndexed();
}
public function iterateColumn(string $query, array $params = [], array $types = []) : Traversable
{
return $this->executeQuery($query, $params, $types)->iterateColumn();
}
public function prepare(string $sql) : Statement
{
$connection = $this->getWrappedConnection();
try {
$statement = $connection->prepare($sql);
} catch (Driver\Exception $e) {
throw $this->convertExceptionDuringQuery($e, $sql);
}
return new Statement($this, $statement, $sql);
}
public function executeQuery(string $sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : Result
{
if ($qcp !== null) {
return $this->executeCacheQuery($sql, $params, $types, $qcp);
}
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger !== null) {
$logger->startQuery($sql, $params, $types);
}
try {
if (count($params) > 0) {
if ($this->needsArrayParameterConversion($params, $types)) {
[$sql, $params, $types] = $this->expandArrayParameters($sql, $params, $types);
}
$stmt = $connection->prepare($sql);
$this->bindParameters($stmt, $params, $types);
$result = $stmt->execute();
} else {
$result = $connection->query($sql);
}
return new Result($result, $this);
} catch (Driver\Exception $e) {
throw $this->convertExceptionDuringQuery($e, $sql, $params, $types);
} finally {
if ($logger !== null) {
$logger->stopQuery();
}
}
}
public function executeCacheQuery($sql, $params, $types, QueryCacheProfile $qcp) : Result
{
$resultCache = $qcp->getResultCache() ?? $this->_config->getResultCache();
if ($resultCache === null) {
throw CacheException::noResultDriverConfigured();
}
$connectionParams = $this->params;
unset($connectionParams['platform'], $connectionParams['password'], $connectionParams['url']);
[$cacheKey, $realKey] = $qcp->generateCacheKeys($sql, $params, $types, $connectionParams);
$item = $resultCache->getItem($cacheKey);
if ($item->isHit()) {
$value = $item->get();
if (!is_array($value)) {
$value = [];
}
if (isset($value[$realKey])) {
return new Result(new ArrayResult($value[$realKey]), $this);
}
} else {
$value = [];
}
$data = $this->fetchAllAssociative($sql, $params, $types);
$value[$realKey] = $data;
$item->set($value);
$lifetime = $qcp->getLifetime();
if ($lifetime > 0) {
$item->expiresAfter($lifetime);
}
$resultCache->save($item);
return new Result(new ArrayResult($data), $this);
}
public function executeStatement($sql, array $params = [], array $types = [])
{
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($logger !== null) {
$logger->startQuery($sql, $params, $types);
}
try {
if (count($params) > 0) {
if ($this->needsArrayParameterConversion($params, $types)) {
[$sql, $params, $types] = $this->expandArrayParameters($sql, $params, $types);
}
$stmt = $connection->prepare($sql);
$this->bindParameters($stmt, $params, $types);
return $stmt->execute()->rowCount();
}
return $connection->exec($sql);
} catch (Driver\Exception $e) {
throw $this->convertExceptionDuringQuery($e, $sql, $params, $types);
} finally {
if ($logger !== null) {
$logger->stopQuery();
}
}
}
public function getTransactionNestingLevel()
{
return $this->transactionNestingLevel;
}
public function lastInsertId($name = null)
{
if ($name !== null) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4687', 'The usage of Connection::lastInsertId() with a sequence name is deprecated.');
}
try {
return $this->getWrappedConnection()->lastInsertId($name);
} catch (Driver\Exception $e) {
throw $this->convertException($e);
}
}
public function transactional(Closure $func)
{
$this->beginTransaction();
try {
$res = $func($this);
$this->commit();
return $res;
} catch (Throwable $e) {
$this->rollBack();
throw $e;
}
}
public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints)
{
if (!$nestTransactionsWithSavepoints) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5383', <<<'DEPRECATION'
Nesting transactions without enabling savepoints is deprecated.
Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
DEPRECATION
, self::class);
}
if ($this->transactionNestingLevel > 0) {
throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction();
}
$this->nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints;
}
public function getNestTransactionsWithSavepoints()
{
return $this->nestTransactionsWithSavepoints;
}
protected function _getNestedTransactionSavePointName()
{
return 'DOCTRINE_' . $this->transactionNestingLevel;
}
public function beginTransaction()
{
$connection = $this->getWrappedConnection();
++$this->transactionNestingLevel;
$logger = $this->_config->getSQLLogger();
if ($this->transactionNestingLevel === 1) {
if ($logger !== null) {
$logger->startQuery('"START TRANSACTION"');
}
$connection->beginTransaction();
if ($logger !== null) {
$logger->stopQuery();
}
} elseif ($this->nestTransactionsWithSavepoints) {
if ($logger !== null) {
$logger->startQuery('"SAVEPOINT"');
}
$this->createSavepoint($this->_getNestedTransactionSavePointName());
if ($logger !== null) {
$logger->stopQuery();
}
} else {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5383', <<<'DEPRECATION'
Nesting transactions without enabling savepoints is deprecated.
Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
DEPRECATION
, self::class);
}
$eventManager = $this->getEventManager();
if ($eventManager->hasListeners(Events::onTransactionBegin)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5784', 'Subscribing to %s events is deprecated.', Events::onTransactionBegin);
$eventManager->dispatchEvent(Events::onTransactionBegin, new TransactionBeginEventArgs($this));
}
return \true;
}
public function commit()
{
if ($this->transactionNestingLevel === 0) {
throw ConnectionException::noActiveTransaction();
}
if ($this->isRollbackOnly) {
throw ConnectionException::commitFailedRollbackOnly();
}
$result = \true;
$connection = $this->getWrappedConnection();
if ($this->transactionNestingLevel === 1) {
$result = $this->doCommit($connection);
} elseif ($this->nestTransactionsWithSavepoints) {
$this->releaseSavepoint($this->_getNestedTransactionSavePointName());
}
--$this->transactionNestingLevel;
$eventManager = $this->getEventManager();
if ($eventManager->hasListeners(Events::onTransactionCommit)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5784', 'Subscribing to %s events is deprecated.', Events::onTransactionCommit);
$eventManager->dispatchEvent(Events::onTransactionCommit, new TransactionCommitEventArgs($this));
}
if ($this->autoCommit !== \false || $this->transactionNestingLevel !== 0) {
return $result;
}
$this->beginTransaction();
return $result;
}
private function doCommit(DriverConnection $connection)
{
$logger = $this->_config->getSQLLogger();
if ($logger !== null) {
$logger->startQuery('"COMMIT"');
}
$result = $connection->commit();
if ($logger !== null) {
$logger->stopQuery();
}
return $result;
}
private function commitAll() : void
{
while ($this->transactionNestingLevel !== 0) {
if ($this->autoCommit === \false && $this->transactionNestingLevel === 1) {
// When in no auto-commit mode, the last nesting commit immediately starts a new transaction.
// Therefore we need to do the final commit here and then leave to avoid an infinite loop.
$this->commit();
return;
}
$this->commit();
}
}
public function rollBack()
{
if ($this->transactionNestingLevel === 0) {
throw ConnectionException::noActiveTransaction();
}
$connection = $this->getWrappedConnection();
$logger = $this->_config->getSQLLogger();
if ($this->transactionNestingLevel === 1) {
if ($logger !== null) {
$logger->startQuery('"ROLLBACK"');
}
$this->transactionNestingLevel = 0;
$connection->rollBack();
$this->isRollbackOnly = \false;
if ($logger !== null) {
$logger->stopQuery();
}
if ($this->autoCommit === \false) {
$this->beginTransaction();
}
} elseif ($this->nestTransactionsWithSavepoints) {
if ($logger !== null) {
$logger->startQuery('"ROLLBACK TO SAVEPOINT"');
}
$this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
--$this->transactionNestingLevel;
if ($logger !== null) {
$logger->stopQuery();
}
} else {
$this->isRollbackOnly = \true;
--$this->transactionNestingLevel;
}
$eventManager = $this->getEventManager();
if ($eventManager->hasListeners(Events::onTransactionRollBack)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/5784', 'Subscribing to %s events is deprecated.', Events::onTransactionRollBack);
$eventManager->dispatchEvent(Events::onTransactionRollBack, new TransactionRollBackEventArgs($this));
}
return \true;
}
public function createSavepoint($savepoint)
{
$platform = $this->getDatabasePlatform();
if (!$platform->supportsSavepoints()) {
throw ConnectionException::savepointsNotSupported();
}
$this->executeStatement($platform->createSavePoint($savepoint));
}
public function releaseSavepoint($savepoint)
{
$logger = $this->_config->getSQLLogger();
$platform = $this->getDatabasePlatform();
if (!$platform->supportsSavepoints()) {
throw ConnectionException::savepointsNotSupported();
}
if (!$platform->supportsReleaseSavepoints()) {
if ($logger !== null) {
$logger->stopQuery();
}
return;
}
if ($logger !== null) {
$logger->startQuery('"RELEASE SAVEPOINT"');
}
$this->executeStatement($platform->releaseSavePoint($savepoint));
if ($logger === null) {
return;
}
$logger->stopQuery();
}
public function rollbackSavepoint($savepoint)
{
$platform = $this->getDatabasePlatform();
if (!$platform->supportsSavepoints()) {
throw ConnectionException::savepointsNotSupported();
}
$this->executeStatement($platform->rollbackSavePoint($savepoint));
}
public function getWrappedConnection()
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4966', 'Connection::getWrappedConnection() is deprecated.' . ' Use Connection::getNativeConnection() to access the native connection.');
$this->connect();
return $this->_conn;
}
public function getNativeConnection()
{
$this->connect();
if (!method_exists($this->_conn, 'getNativeConnection')) {
throw new LogicException(sprintf('The driver connection %s does not support accessing the native connection.', get_class($this->_conn)));
}
return $this->_conn->getNativeConnection();
}
public function createSchemaManager() : AbstractSchemaManager
{
return $this->schemaManagerFactory->createSchemaManager($this);
}
public function getSchemaManager()
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4515', 'Connection::getSchemaManager() is deprecated, use Connection::createSchemaManager() instead.');
return $this->_schemaManager ??= $this->createSchemaManager();
}
public function setRollbackOnly()
{
if ($this->transactionNestingLevel === 0) {
throw ConnectionException::noActiveTransaction();
}
$this->isRollbackOnly = \true;
}
public function isRollbackOnly()
{
if ($this->transactionNestingLevel === 0) {
throw ConnectionException::noActiveTransaction();
}
return $this->isRollbackOnly;
}
public function convertToDatabaseValue($value, $type)
{
return Type::getType($type)->convertToDatabaseValue($value, $this->getDatabasePlatform());
}
public function convertToPHPValue($value, $type)
{
return Type::getType($type)->convertToPHPValue($value, $this->getDatabasePlatform());
}
private function bindParameters(DriverStatement $stmt, array $params, array $types) : void
{
// Check whether parameters are positional or named. Mixing is not allowed.
if (is_int(key($params))) {
$bindIndex = 1;
foreach ($params as $key => $value) {
if (isset($types[$key])) {
$type = $types[$key];
[$value, $bindingType] = $this->getBindingInfo($value, $type);
} else {
if (array_key_exists($key, $types)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5550', 'Using NULL as prepared statement parameter type is deprecated.' . 'Omit or use ParameterType::STRING instead');
}
$bindingType = ParameterType::STRING;
}
$stmt->bindValue($bindIndex, $value, $bindingType);
++$bindIndex;
}
} else {
// Named parameters
foreach ($params as $name => $value) {
if (isset($types[$name])) {
$type = $types[$name];
[$value, $bindingType] = $this->getBindingInfo($value, $type);
} else {
if (array_key_exists($name, $types)) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5550', 'Using NULL as prepared statement parameter type is deprecated.' . 'Omit or use ParameterType::STRING instead');
}
$bindingType = ParameterType::STRING;
}
$stmt->bindValue($name, $value, $bindingType);
}
}
}
private function getBindingInfo($value, $type) : array
{
if (is_string($type)) {
$type = Type::getType($type);
}
if ($type instanceof Type) {
$value = $type->convertToDatabaseValue($value, $this->getDatabasePlatform());
$bindingType = $type->getBindingType();
} else {
$bindingType = $type ?? ParameterType::STRING;
}
return [$value, $bindingType];
}
public function createQueryBuilder()
{
return new Query\QueryBuilder($this);
}
public final function convertExceptionDuringQuery(Driver\Exception $e, string $sql, array $params = [], array $types = []) : DriverException
{
return $this->handleDriverException($e, new Query($sql, $params, $types));
}
public final function convertException(Driver\Exception $e) : DriverException
{
return $this->handleDriverException($e, null);
}
private function expandArrayParameters(string $sql, array $params, array $types) : array
{
$this->parser ??= $this->getDatabasePlatform()->createSQLParser();
$visitor = new ExpandArrayParameters($params, $types);
$this->parser->parse($sql, $visitor);
return [$visitor->getSQL(), $visitor->getParameters(), $visitor->getTypes()];
}
private function needsArrayParameterConversion(array $params, array $types) : bool
{
if (is_string(key($params))) {
return \true;
}
foreach ($types as $type) {
if ($type === ArrayParameterType::INTEGER || $type === ArrayParameterType::STRING || $type === ArrayParameterType::ASCII || $type === ArrayParameterType::BINARY) {
return \true;
}
}
return \false;
}
private function handleDriverException(Driver\Exception $driverException, ?Query $query) : DriverException
{
$this->exceptionConverter ??= $this->_driver->getExceptionConverter();
$exception = $this->exceptionConverter->convert($driverException, $query);
if ($exception instanceof ConnectionLost) {
$this->close();
}
return $exception;
}
public function executeUpdate(string $sql, array $params = [], array $types = []) : int
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4163', '%s is deprecated, please use executeStatement() instead.', __METHOD__);
return $this->executeStatement($sql, $params, $types);
}
public function query(string $sql) : Result
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4163', '%s is deprecated, please use executeQuery() instead.', __METHOD__);
return $this->executeQuery($sql);
}
public function exec(string $sql) : int
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4163', '%s is deprecated, please use executeStatement() instead.', __METHOD__);
return $this->executeStatement($sql);
}
}
@@ -0,0 +1,22 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
class ConnectionException extends Exception
{
public static function commitFailedRollbackOnly()
{
return new self('Transaction commit failed because the transaction has been marked for rollback only.');
}
public static function noActiveTransaction()
{
return new self('There is no active transaction.');
}
public static function savepointsNotSupported()
{
return new self('Savepoints are not supported by this driver.');
}
public static function mayNotAlterNestedTransactionWithSavepointsInTransaction()
{
return new self('May not alter the nested transaction with savepoints behavior while a transaction is open.');
}
}
@@ -0,0 +1,16 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\API\ExceptionConverter;
use MailPoetVendor\Doctrine\DBAL\Driver\Connection as DriverConnection;
use MailPoetVendor\Doctrine\DBAL\Driver\Exception;
use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractPlatform;
use MailPoetVendor\Doctrine\DBAL\Schema\AbstractSchemaManager;
use MailPoetVendor\SensitiveParameter;
interface Driver
{
public function connect( array $params);
public function getDatabasePlatform();
public function getSchemaManager(Connection $conn, AbstractPlatform $platform);
public function getExceptionConverter() : ExceptionConverter;
}
@@ -0,0 +1,11 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver\API;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\Exception;
use MailPoetVendor\Doctrine\DBAL\Exception\DriverException;
use MailPoetVendor\Doctrine\DBAL\Query;
interface ExceptionConverter
{
public function convert(Exception $exception, ?Query $query) : DriverException;
}
@@ -0,0 +1,98 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver\API\MySQL;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
use MailPoetVendor\Doctrine\DBAL\Driver\Exception;
use MailPoetVendor\Doctrine\DBAL\Exception\ConnectionException;
use MailPoetVendor\Doctrine\DBAL\Exception\ConnectionLost;
use MailPoetVendor\Doctrine\DBAL\Exception\DatabaseDoesNotExist;
use MailPoetVendor\Doctrine\DBAL\Exception\DeadlockException;
use MailPoetVendor\Doctrine\DBAL\Exception\DriverException;
use MailPoetVendor\Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use MailPoetVendor\Doctrine\DBAL\Exception\InvalidFieldNameException;
use MailPoetVendor\Doctrine\DBAL\Exception\LockWaitTimeoutException;
use MailPoetVendor\Doctrine\DBAL\Exception\NonUniqueFieldNameException;
use MailPoetVendor\Doctrine\DBAL\Exception\NotNullConstraintViolationException;
use MailPoetVendor\Doctrine\DBAL\Exception\SyntaxErrorException;
use MailPoetVendor\Doctrine\DBAL\Exception\TableExistsException;
use MailPoetVendor\Doctrine\DBAL\Exception\TableNotFoundException;
use MailPoetVendor\Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use MailPoetVendor\Doctrine\DBAL\Query;
final class ExceptionConverter implements ExceptionConverterInterface
{
public function convert(Exception $exception, ?Query $query) : DriverException
{
switch ($exception->getCode()) {
case 1008:
return new DatabaseDoesNotExist($exception, $query);
case 1213:
return new DeadlockException($exception, $query);
case 1205:
return new LockWaitTimeoutException($exception, $query);
case 1050:
return new TableExistsException($exception, $query);
case 1051:
case 1146:
return new TableNotFoundException($exception, $query);
case 1216:
case 1217:
case 1451:
case 1452:
case 1701:
return new ForeignKeyConstraintViolationException($exception, $query);
case 1062:
case 1557:
case 1569:
case 1586:
return new UniqueConstraintViolationException($exception, $query);
case 1054:
case 1166:
case 1611:
return new InvalidFieldNameException($exception, $query);
case 1052:
case 1060:
case 1110:
return new NonUniqueFieldNameException($exception, $query);
case 1064:
case 1149:
case 1287:
case 1341:
case 1342:
case 1343:
case 1344:
case 1382:
case 1479:
case 1541:
case 1554:
case 1626:
return new SyntaxErrorException($exception, $query);
case 1044:
case 1045:
case 1046:
case 1049:
case 1095:
case 1142:
case 1143:
case 1227:
case 1370:
case 1429:
case 2002:
case 2005:
case 2054:
return new ConnectionException($exception, $query);
case 2006:
return new ConnectionLost($exception, $query);
case 1048:
case 1121:
case 1138:
case 1171:
case 1252:
case 1263:
case 1364:
case 1566:
return new NotNullConstraintViolationException($exception, $query);
}
return new DriverException($exception, $query);
}
}
@@ -0,0 +1,19 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use Exception as BaseException;
use Throwable;
abstract class AbstractException extends BaseException implements Exception
{
private ?string $sqlState = null;
public function __construct($message, $sqlState = null, $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->sqlState = $sqlState;
}
public function getSQLState()
{
return $this->sqlState;
}
}
@@ -0,0 +1,99 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Connection;
use MailPoetVendor\Doctrine\DBAL\Driver\API\ExceptionConverter;
use MailPoetVendor\Doctrine\DBAL\Driver\API\MySQL;
use MailPoetVendor\Doctrine\DBAL\Exception;
use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractPlatform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MariaDb1027Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MariaDb1043Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MariaDb1052Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MariaDb1060Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MySQL57Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MySQL80Platform;
use MailPoetVendor\Doctrine\DBAL\Platforms\MySQLPlatform;
use MailPoetVendor\Doctrine\DBAL\Schema\MySQLSchemaManager;
use MailPoetVendor\Doctrine\DBAL\VersionAwarePlatformDriver;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use function assert;
use function preg_match;
use function stripos;
use function version_compare;
abstract class AbstractMySQLDriver implements VersionAwarePlatformDriver
{
public function createDatabasePlatformForVersion($version)
{
$mariadb = stripos($version, 'mariadb') !== \false;
if ($mariadb) {
$mariaDbVersion = $this->getMariaDbMysqlVersionNumber($version);
if (version_compare($mariaDbVersion, '10.6.0', '>=')) {
return new MariaDb1060Platform();
}
if (version_compare($mariaDbVersion, '10.5.2', '>=')) {
return new MariaDb1052Platform();
}
if (version_compare($mariaDbVersion, '10.4.3', '>=')) {
return new MariaDb1043Platform();
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/6110', 'Support for MariaDB < 10.4 is deprecated and will be removed in DBAL 4.' . ' Consider upgrading to a more recent version of MariaDB.');
if (version_compare($mariaDbVersion, '10.2.7', '>=')) {
return new MariaDb1027Platform();
}
} else {
$oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version);
if (version_compare($oracleMysqlVersion, '8', '>=')) {
if (!version_compare($version, '8.0.0', '>=')) {
Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/dbal/pull/5779', 'Version detection logic for MySQL will change in DBAL 4. ' . 'Please specify the version as the server reports it, e.g. "8.0.31" instead of "8".');
}
return new MySQL80Platform();
}
if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) {
if (!version_compare($version, '5.7.9', '>=')) {
Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/dbal/pull/5779', 'Version detection logic for MySQL will change in DBAL 4. ' . 'Please specify the version as the server reports it, e.g. "5.7.40" instead of "5.7".');
}
return new MySQL57Platform();
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5072', 'MySQL 5.6 support is deprecated and will be removed in DBAL 4.' . ' Consider upgrading to MySQL 5.7 or later.');
}
return $this->getDatabasePlatform();
}
private function getOracleMysqlVersionNumber(string $versionString) : string
{
if (preg_match('/^(?P<major>\\d+)(?:\\.(?P<minor>\\d+)(?:\\.(?P<patch>\\d+))?)?/', $versionString, $versionParts) === 0) {
throw Exception::invalidPlatformVersionSpecified($versionString, '<major_version>.<minor_version>.<patch_version>');
}
$majorVersion = $versionParts['major'];
$minorVersion = $versionParts['minor'] ?? 0;
$patchVersion = $versionParts['patch'] ?? null;
if ($majorVersion === '5' && $minorVersion === '7') {
$patchVersion ??= '9';
}
return $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
}
private function getMariaDbMysqlVersionNumber(string $versionString) : string
{
if (stripos($versionString, 'MariaDB') === 0) {
Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/dbal/pull/5779', 'Version detection logic for MySQL will change in DBAL 4. ' . 'Please specify the version as the server reports it, ' . 'e.g. "10.9.3-MariaDB" instead of "mariadb-10.9".');
}
if (preg_match('/^(?:5\\.5\\.5-)?(mariadb-)?(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)/i', $versionString, $versionParts) === 0) {
throw Exception::invalidPlatformVersionSpecified($versionString, '^(?:5\\.5\\.5-)?(mariadb-)?<major_version>.<minor_version>.<patch_version>');
}
return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
}
public function getDatabasePlatform()
{
return new MySQLPlatform();
}
public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5458', 'AbstractMySQLDriver::getSchemaManager() is deprecated.' . ' Use MySQLPlatform::createSchemaManager() instead.');
assert($platform instanceof AbstractMySQLPlatform);
return new MySQLSchemaManager($conn, $platform);
}
public function getExceptionConverter() : ExceptionConverter
{
return new MySQL\ExceptionConverter();
}
}
@@ -0,0 +1,15 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\ParameterType;
interface Connection
{
public function prepare(string $sql) : Statement;
public function query(string $sql) : Result;
public function quote($value, $type = ParameterType::STRING);
public function exec(string $sql) : int;
public function lastInsertId($name = null);
public function beginTransaction();
public function commit();
public function rollBack();
}
@@ -0,0 +1,9 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use Throwable;
interface Exception extends Throwable
{
public function getSQLState();
}
@@ -0,0 +1,13 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver\Exception;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\AbstractException;
use function sprintf;
final class UnknownParameterType extends AbstractException
{
public static function new($type) : self
{
return new self(sprintf('Unknown parameter type, %d given.', $type));
}
}
@@ -0,0 +1,39 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
final class FetchUtils
{
public static function fetchOne(Result $result)
{
$row = $result->fetchNumeric();
if ($row === \false) {
return \false;
}
return $row[0];
}
public static function fetchAllNumeric(Result $result) : array
{
$rows = [];
while (($row = $result->fetchNumeric()) !== \false) {
$rows[] = $row;
}
return $rows;
}
public static function fetchAllAssociative(Result $result) : array
{
$rows = [];
while (($row = $result->fetchAssociative()) !== \false) {
$rows[] = $row;
}
return $rows;
}
public static function fetchFirstColumn(Result $result) : array
{
$rows = [];
while (($row = $result->fetchOne()) !== \false) {
$rows[] = $row;
}
return $rows;
}
}
@@ -0,0 +1,9 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver;
interface Middleware
{
public function wrap(Driver $driver) : Driver;
}
@@ -0,0 +1,70 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver\Middleware;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\Connection;
use MailPoetVendor\Doctrine\DBAL\Driver\Result;
use MailPoetVendor\Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use MailPoetVendor\Doctrine\DBAL\Driver\Statement;
use MailPoetVendor\Doctrine\DBAL\ParameterType;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use LogicException;
use function get_class;
use function method_exists;
use function sprintf;
abstract class AbstractConnectionMiddleware implements ServerInfoAwareConnection
{
private Connection $wrappedConnection;
public function __construct(Connection $wrappedConnection)
{
$this->wrappedConnection = $wrappedConnection;
}
public function prepare(string $sql) : Statement
{
return $this->wrappedConnection->prepare($sql);
}
public function query(string $sql) : Result
{
return $this->wrappedConnection->query($sql);
}
public function quote($value, $type = ParameterType::STRING)
{
return $this->wrappedConnection->quote($value, $type);
}
public function exec(string $sql) : int
{
return $this->wrappedConnection->exec($sql);
}
public function lastInsertId($name = null)
{
if ($name !== null) {
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/issues/4687', 'The usage of Connection::lastInsertId() with a sequence name is deprecated.');
}
return $this->wrappedConnection->lastInsertId($name);
}
public function beginTransaction()
{
return $this->wrappedConnection->beginTransaction();
}
public function commit()
{
return $this->wrappedConnection->commit();
}
public function rollBack()
{
return $this->wrappedConnection->rollBack();
}
public function getServerVersion()
{
if (!$this->wrappedConnection instanceof ServerInfoAwareConnection) {
throw new LogicException('The underlying connection is not a ServerInfoAwareConnection');
}
return $this->wrappedConnection->getServerVersion();
}
public function getNativeConnection()
{
if (!method_exists($this->wrappedConnection, 'getNativeConnection')) {
throw new LogicException(sprintf('The driver connection %s does not support accessing the native connection.', get_class($this->wrappedConnection)));
}
return $this->wrappedConnection->getNativeConnection();
}
}
@@ -0,0 +1,42 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver\Middleware;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Connection;
use MailPoetVendor\Doctrine\DBAL\Driver;
use MailPoetVendor\Doctrine\DBAL\Driver\API\ExceptionConverter;
use MailPoetVendor\Doctrine\DBAL\Platforms\AbstractPlatform;
use MailPoetVendor\Doctrine\DBAL\VersionAwarePlatformDriver;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use MailPoetVendor\SensitiveParameter;
abstract class AbstractDriverMiddleware implements VersionAwarePlatformDriver
{
private Driver $wrappedDriver;
public function __construct(Driver $wrappedDriver)
{
$this->wrappedDriver = $wrappedDriver;
}
public function connect( array $params)
{
return $this->wrappedDriver->connect($params);
}
public function getDatabasePlatform()
{
return $this->wrappedDriver->getDatabasePlatform();
}
public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
{
Deprecation::triggerIfCalledFromOutside('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5458', 'AbstractDriverMiddleware::getSchemaManager() is deprecated.' . ' Use AbstractPlatform::createSchemaManager() instead.');
return $this->wrappedDriver->getSchemaManager($conn, $platform);
}
public function getExceptionConverter() : ExceptionConverter
{
return $this->wrappedDriver->getExceptionConverter();
}
public function createDatabasePlatformForVersion($version)
{
if ($this->wrappedDriver instanceof VersionAwarePlatformDriver) {
return $this->wrappedDriver->createDatabasePlatformForVersion($version);
}
return $this->wrappedDriver->getDatabasePlatform();
}
}
@@ -0,0 +1,48 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver\Middleware;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\Result;
abstract class AbstractResultMiddleware implements Result
{
private Result $wrappedResult;
public function __construct(Result $result)
{
$this->wrappedResult = $result;
}
public function fetchNumeric()
{
return $this->wrappedResult->fetchNumeric();
}
public function fetchAssociative()
{
return $this->wrappedResult->fetchAssociative();
}
public function fetchOne()
{
return $this->wrappedResult->fetchOne();
}
public function fetchAllNumeric() : array
{
return $this->wrappedResult->fetchAllNumeric();
}
public function fetchAllAssociative() : array
{
return $this->wrappedResult->fetchAllAssociative();
}
public function fetchFirstColumn() : array
{
return $this->wrappedResult->fetchFirstColumn();
}
public function rowCount() : int
{
return $this->wrappedResult->rowCount();
}
public function columnCount() : int
{
return $this->wrappedResult->columnCount();
}
public function free() : void
{
$this->wrappedResult->free();
}
}
@@ -0,0 +1,35 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver\Middleware;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\Driver\Result;
use MailPoetVendor\Doctrine\DBAL\Driver\Statement;
use MailPoetVendor\Doctrine\DBAL\ParameterType;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use function func_num_args;
abstract class AbstractStatementMiddleware implements Statement
{
private Statement $wrappedStatement;
public function __construct(Statement $wrappedStatement)
{
$this->wrappedStatement = $wrappedStatement;
}
public function bindValue($param, $value, $type = ParameterType::STRING)
{
if (func_num_args() < 3) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5558', 'Not passing $type to Statement::bindValue() is deprecated.' . ' Pass the type corresponding to the parameter being bound.');
}
return $this->wrappedStatement->bindValue($param, $value, $type);
}
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
{
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5563', '%s is deprecated. Use bindValue() instead.', __METHOD__);
if (func_num_args() < 3) {
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5558', 'Not passing $type to Statement::bindParam() is deprecated.' . ' Pass the type corresponding to the parameter being bound.');
}
return $this->wrappedStatement->bindParam($param, $variable, $type, $length);
}
public function execute($params = null) : Result
{
return $this->wrappedStatement->execute($params);
}
}
@@ -0,0 +1,16 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
interface Result
{
public function fetchNumeric();
public function fetchAssociative();
public function fetchOne();
public function fetchAllNumeric() : array;
public function fetchAllAssociative() : array;
public function fetchFirstColumn() : array;
public function rowCount() : int;
public function columnCount() : int;
public function free() : void;
}
@@ -0,0 +1,7 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
interface ServerInfoAwareConnection extends Connection
{
public function getServerVersion();
}
@@ -0,0 +1,10 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Driver;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\DBAL\ParameterType;
interface Statement
{
public function bindValue($param, $value, $type = ParameterType::STRING);
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null);
public function execute($params = null) : Result;
}
@@ -0,0 +1,106 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\EventManager;
use MailPoetVendor\Doctrine\DBAL\Driver\IBMDB2;
use MailPoetVendor\Doctrine\DBAL\Driver\Mysqli;
use MailPoetVendor\Doctrine\DBAL\Driver\OCI8;
use MailPoetVendor\Doctrine\DBAL\Driver\PDO;
use MailPoetVendor\Doctrine\DBAL\Driver\PgSQL;
use MailPoetVendor\Doctrine\DBAL\Driver\SQLite3;
use MailPoetVendor\Doctrine\DBAL\Driver\SQLSrv;
use MailPoetVendor\Doctrine\DBAL\Exception\MalformedDsnException;
use MailPoetVendor\Doctrine\DBAL\Tools\DsnParser;
use MailPoetVendor\Doctrine\Deprecations\Deprecation;
use MailPoetVendor\SensitiveParameter;
use function array_keys;
use function array_merge;
use function is_a;
final class DriverManager
{
private const DRIVER_MAP = ['pdo_mysql' => PDO\MySQL\Driver::class, 'pdo_sqlite' => PDO\SQLite\Driver::class, 'pdo_pgsql' => PDO\PgSQL\Driver::class, 'pdo_oci' => PDO\OCI\Driver::class, 'oci8' => OCI8\Driver::class, 'ibm_db2' => IBMDB2\Driver::class, 'pdo_sqlsrv' => PDO\SQLSrv\Driver::class, 'mysqli' => Mysqli\Driver::class, 'pgsql' => PgSQL\Driver::class, 'sqlsrv' => SQLSrv\Driver::class, 'sqlite3' => SQLite3\Driver::class];
private static array $driverSchemeAliases = [
'db2' => 'ibm_db2',
'mssql' => 'pdo_sqlsrv',
'mysql' => 'pdo_mysql',
'mysql2' => 'pdo_mysql',
// Amazon RDS, for some weird reason
'postgres' => 'pdo_pgsql',
'postgresql' => 'pdo_pgsql',
'pgsql' => 'pdo_pgsql',
'sqlite' => 'pdo_sqlite',
'sqlite3' => 'pdo_sqlite',
];
private function __construct()
{
}
public static function getConnection( array $params, ?Configuration $config = null, ?EventManager $eventManager = null) : Connection
{
// create default config and event manager, if not set
$config ??= new Configuration();
$eventManager ??= new EventManager();
$params = self::parseDatabaseUrl($params);
// URL support for PrimaryReplicaConnection
if (isset($params['primary'])) {
$params['primary'] = self::parseDatabaseUrl($params['primary']);
}
if (isset($params['replica'])) {
foreach ($params['replica'] as $key => $replicaParams) {
$params['replica'][$key] = self::parseDatabaseUrl($replicaParams);
}
}
$driver = self::createDriver($params['driver'] ?? null, $params['driverClass'] ?? null);
foreach ($config->getMiddlewares() as $middleware) {
$driver = $middleware->wrap($driver);
}
$wrapperClass = $params['wrapperClass'] ?? Connection::class;
if (!is_a($wrapperClass, Connection::class, \true)) {
throw Exception::invalidWrapperClass($wrapperClass);
}
return new $wrapperClass($params, $driver, $config, $eventManager);
}
public static function getAvailableDrivers() : array
{
return array_keys(self::DRIVER_MAP);
}
private static function createDriver(?string $driver, ?string $driverClass) : Driver
{
if ($driverClass === null) {
if ($driver === null) {
throw Exception::driverRequired();
}
if (!isset(self::DRIVER_MAP[$driver])) {
throw Exception::unknownDriver($driver, array_keys(self::DRIVER_MAP));
}
$driverClass = self::DRIVER_MAP[$driver];
} elseif (!is_a($driverClass, Driver::class, \true)) {
throw Exception::invalidDriverClass($driverClass);
}
return new $driverClass();
}
private static function parseDatabaseUrl( array $params) : array
{
if (!isset($params['url'])) {
return $params;
}
Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/5843', 'The "url" connection parameter is deprecated. Please use %s to parse a database url before calling %s.', DsnParser::class, self::class);
$parser = new DsnParser(self::$driverSchemeAliases);
try {
$parsedParams = $parser->parse($params['url']);
} catch (MalformedDsnException $e) {
throw new Exception('Malformed parameter "url".', 0, $e);
}
if (isset($parsedParams['driver'])) {
// The requested driver from the URL scheme takes precedence
// over the default custom driver from the connection parameters (if any).
unset($params['driverClass']);
}
$params = array_merge($params, $parsedParams);
// If a schemeless connection URL is given, we require a default driver or default custom driver
// as connection parameter.
if (!isset($params['driverClass']) && !isset($params['driver'])) {
throw Exception::driverRequired($params['url']);
}
return $params;
}
}
@@ -0,0 +1,23 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Event\Listeners;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\EventSubscriber;
use MailPoetVendor\Doctrine\DBAL\Event\ConnectionEventArgs;
use MailPoetVendor\Doctrine\DBAL\Events;
use MailPoetVendor\Doctrine\DBAL\Exception;
class SQLSessionInit implements EventSubscriber
{
protected $sql;
public function __construct($sql)
{
$this->sql = $sql;
}
public function postConnect(ConnectionEventArgs $args)
{
$args->getConnection()->executeStatement($this->sql);
}
public function getSubscribedEvents()
{
return [Events::postConnect];
}
}
@@ -0,0 +1,18 @@
<?php
namespace MailPoetVendor\Doctrine\DBAL\Event\Listeners;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\EventSubscriber;
use MailPoetVendor\Doctrine\DBAL\Event\ConnectionEventArgs;
use MailPoetVendor\Doctrine\DBAL\Events;
use MailPoetVendor\Doctrine\DBAL\Exception;
class SQLiteSessionInit implements EventSubscriber
{
public function postConnect(ConnectionEventArgs $args)
{
$args->getConnection()->executeStatement('PRAGMA foreign_keys=ON');
}
public function getSubscribedEvents()
{
return [Events::postConnect];
}
}
@@ -0,0 +1,7 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Event;
if (!defined('ABSPATH')) exit;
class TransactionBeginEventArgs extends TransactionEventArgs
{
}
@@ -0,0 +1,7 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Event;
if (!defined('ABSPATH')) exit;
class TransactionCommitEventArgs extends TransactionEventArgs
{
}
@@ -0,0 +1,18 @@
<?php
declare (strict_types=1);
namespace MailPoetVendor\Doctrine\DBAL\Event;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Doctrine\Common\EventArgs;
use MailPoetVendor\Doctrine\DBAL\Connection;
abstract class TransactionEventArgs extends EventArgs
{
private Connection $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function getConnection() : Connection
{
return $this->connection;
}
}

Some files were not shown because too many files have changed in this diff Show More