Merge pull request #8651 from alcaeus/deprecate-doctrine-metadata-cache

Introduce PSR-6 for metadata caching
This commit is contained in:
Grégoire Paris
2021-05-01 14:53:46 +02:00
committed by GitHub
7 changed files with 134 additions and 26 deletions

View File

@@ -20,7 +20,7 @@
"ext-pdo": "*",
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.12",
"doctrine/cache": "^1.9.1",
"doctrine/cache": "^1.11.0",
"doctrine/collections": "^1.5",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.13.0",
@@ -30,6 +30,7 @@
"doctrine/instantiator": "^1.3",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^2.0",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^3.0|^4.0|^5.0"
},
"require-dev": {
@@ -37,6 +38,7 @@
"phpstan/phpstan": "^0.12.83",
"phpunit/phpunit": "^7.5|^8.5|^9.4",
"squizlabs/php_codesniffer": "3.6.0",
"symfony/cache": "^4.4|^5.2",
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "4.7.0"
},

View File

@@ -27,6 +27,7 @@ use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
@@ -41,6 +42,7 @@ use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\ObjectRepository;
use Psr\Cache\CacheItemPoolInterface;
use ReflectionClass;
use function strtolower;
@@ -282,23 +284,51 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* Gets the cache driver implementation that is used for metadata caching.
*
* @deprecated Deprecated in favor of getMetadataCache
*
* @return CacheDriver|null
*/
public function getMetadataCacheImpl()
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8650',
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getMetadataCache() instead.',
__METHOD__
);
return $this->_attributes['metadataCacheImpl'] ?? null;
}
/**
* Sets the cache driver implementation that is used for metadata caching.
*
* @deprecated Deprecated in favor of setMetadataCache
*
* @return void
*/
public function setMetadataCacheImpl(CacheDriver $cacheImpl)
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8650',
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use setMetadataCache() instead.',
__METHOD__
);
$this->_attributes['metadataCacheImpl'] = $cacheImpl;
}
public function getMetadataCache(): ?CacheItemPoolInterface
{
return $this->_attributes['metadataCache'] ?? null;
}
public function setMetadataCache(CacheItemPoolInterface $cache): void
{
$this->_attributes['metadataCache'] = $cache;
}
/**
* Adds a named DQL query to the configuration.
*
@@ -387,6 +417,14 @@ class Configuration extends \Doctrine\DBAL\Configuration
throw ORMException::queryCacheUsesNonPersistentCache($queryCacheImpl);
}
if ($this->getAutoGenerateProxyClasses()) {
throw ORMException::proxyClassesAlwaysRegenerating();
}
if ($this->getMetadataCache()) {
return;
}
$metadataCacheImpl = $this->getMetadataCacheImpl();
if (! $metadataCacheImpl) {
@@ -396,10 +434,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
if ($metadataCacheImpl instanceof ArrayCache) {
throw ORMException::metadataCacheUsesNonPersistentCache($metadataCacheImpl);
}
if ($this->getAutoGenerateProxyClasses()) {
throw ORMException::proxyClassesAlwaysRegenerating();
}
}
/**

View File

@@ -21,6 +21,8 @@
namespace Doctrine\ORM;
use BadMethodCallException;
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\EventManager;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Connection;
@@ -48,6 +50,7 @@ use function is_callable;
use function is_object;
use function is_string;
use function ltrim;
use function method_exists;
use function sprintf;
/**
@@ -164,7 +167,8 @@ use function sprintf;
$this->metadataFactory = new $metadataFactoryClassName();
$this->metadataFactory->setEntityManager($this);
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
$this->configureMetadataCache();
$this->repositoryFactory = $config->getRepositoryFactory();
$this->unitOfWork = new UnitOfWork($this);
@@ -986,4 +990,42 @@ use function sprintf;
}
}
}
private function configureMetadataCache(): void
{
$metadataCache = $this->config->getMetadataCache();
if (! $metadataCache) {
$this->configureLegacyMetadataCache();
return;
}
// We have a PSR-6 compatible metadata factory. Use cache directly
if (method_exists($this->metadataFactory, 'setCache')) {
$this->metadataFactory->setCache($metadataCache);
return;
}
// Wrap PSR-6 cache to provide doctrine/cache interface
$this->metadataFactory->setCacheDriver(DoctrineProvider::wrap($metadataCache));
}
private function configureLegacyMetadataCache(): void
{
$metadataCache = $this->config->getMetadataCacheImpl();
if (! $metadataCache) {
return;
}
// Metadata factory is not PSR-6 compatible. Use cache directly
if (! method_exists($this->metadataFactory, 'setCache')) {
$this->metadataFactory->setCacheDriver($metadataCache);
return;
}
// Wrap doctrine/cache to provide PSR-6 interface
$this->metadataFactory->setCache(CacheAdapter::wrap($metadataCache));
}
}

View File

@@ -17,14 +17,16 @@ use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Tests\DoctrineTestCase;
use Doctrine\Tests\Models\DDC753\DDC753CustomRepository;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemPoolInterface;
use ReflectionClass;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* Tests for the Configuration object
*/
class ConfigurationTest extends TestCase
class ConfigurationTest extends DoctrineTestCase
{
/** @var Configuration */
private $configuration;
@@ -131,6 +133,14 @@ class ConfigurationTest extends TestCase
$this->assertSame($queryCacheImpl, $this->configuration->getMetadataCacheImpl());
}
public function testSetGetMetadataCache(): void
{
$this->assertNull($this->configuration->getMetadataCache());
$cache = $this->createStub(CacheItemPoolInterface::class);
$this->configuration->setMetadataCache($cache);
$this->assertSame($cache, $this->configuration->getMetadataCache());
}
public function testAddGetNamedQuery(): void
{
$dql = 'SELECT u FROM User u';
@@ -182,7 +192,17 @@ class ConfigurationTest extends TestCase
$this->addToAssertionCount(1);
}
public function testEnsureProductionSettingsQueryCache(): void
public function testEnsureProductionSettingsWithNewMetadataCache(): void
{
$this->setProductionSettings('metadata');
$this->configuration->setMetadataCache(new ArrayAdapter());
$this->configuration->ensureProductionSettings();
$this->addToAssertionCount(1);
}
public function testEnsureProductionSettingsMissingQueryCache(): void
{
$this->setProductionSettings('query');
@@ -192,7 +212,7 @@ class ConfigurationTest extends TestCase
$this->configuration->ensureProductionSettings();
}
public function testEnsureProductionSettingsMetadataCache(): void
public function testEnsureProductionSettingsMissingMetadataCache(): void
{
$this->setProductionSettings('metadata');
@@ -213,7 +233,7 @@ class ConfigurationTest extends TestCase
$this->configuration->ensureProductionSettings();
}
public function testEnsureProductionSettingsMetadataArrayCache(): void
public function testEnsureProductionSettingsLegacyMetadataArrayCache(): void
{
$this->setProductionSettings();
$this->configuration->setMetadataCacheImpl(new ArrayCache());

View File

@@ -13,6 +13,7 @@ use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use GearmanWorker;
use InvalidArgumentException;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function assert;
use function is_array;
@@ -121,9 +122,9 @@ class LockAgentWorker
$annotDriver = $config->newDefaultAnnotationDriver([__DIR__ . '/../../../Models/'], true);
$config->setMetadataDriverImpl($annotDriver);
$config->setMetadataCache(new ArrayAdapter());
$cache = new ArrayCache();
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
$config->setSQLLogger(new EchoSQLLogger());

View File

@@ -21,7 +21,9 @@ use Doctrine\Tests\EventListener\CacheMetadataListener;
use Exception;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Warning;
use Psr\Cache\CacheItemPoolInterface;
use RuntimeException;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Throwable;
use function array_map;
@@ -50,9 +52,9 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
/**
* The metadata cache shared between all functional tests.
*
* @var Cache|null
* @var Cache|CacheItemPoolInterface|null
*/
private static $_metadataCacheImpl = null;
private static $_metadataCache = null;
/**
* The query cache shared between all functional tests.
@@ -699,11 +701,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
// NOTE: Functional tests use their own shared metadata cache, because
// the actual database platform used during execution has effect on some
// metadata mapping behaviors (like the choice of the ID generation).
if (self::$_metadataCacheImpl === null) {
if (self::$_metadataCache === null) {
if (isset($GLOBALS['DOCTRINE_CACHE_IMPL'])) {
self::$_metadataCacheImpl = new $GLOBALS['DOCTRINE_CACHE_IMPL']();
self::$_metadataCache = new $GLOBALS['DOCTRINE_CACHE_IMPL']();
} else {
self::$_metadataCacheImpl = new ArrayCache();
self::$_metadataCache = new ArrayAdapter();
}
}
@@ -717,7 +719,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
//FIXME: two different configs! $conn and the created entity manager have
// different configs.
$config = new Configuration();
$config->setMetadataCacheImpl(self::$_metadataCacheImpl);
if (self::$_metadataCache instanceof CacheItemPoolInterface) {
$config->setMetadataCache(self::$_metadataCache);
} else {
$config->setMetadataCacheImpl(self::$_metadataCache);
}
$config->setQueryCacheImpl(self::$_queryCacheImpl);
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Doctrine\Tests\Proxies');

View File

@@ -17,6 +17,8 @@ use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\Tests\Mocks\EntityManagerMock;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function is_array;
use function realpath;
@@ -29,9 +31,9 @@ abstract class OrmTestCase extends DoctrineTestCase
/**
* The metadata cache that is shared between all ORM tests (except functional tests).
*
* @var Cache|null
* @var CacheItemPoolInterface|null
*/
private static $_metadataCacheImpl = null;
private static $_metadataCache = null;
/**
* The query cache that is shared between all ORM tests (except functional tests).
@@ -92,11 +94,11 @@ abstract class OrmTestCase extends DoctrineTestCase
): EntityManagerMock {
$metadataCache = $withSharedMetadata
? self::getSharedMetadataCacheImpl()
: new ArrayCache();
: new ArrayAdapter();
$config = new Configuration();
$config->setMetadataCacheImpl($metadataCache);
$config->setMetadataCache($metadataCache);
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver([], true));
$config->setQueryCacheImpl(self::getSharedQueryCacheImpl());
$config->setProxyDir(__DIR__ . '/Proxies');
@@ -142,13 +144,13 @@ abstract class OrmTestCase extends DoctrineTestCase
$this->isSecondLevelCacheLogEnabled = $log;
}
private static function getSharedMetadataCacheImpl(): Cache
private static function getSharedMetadataCacheImpl(): ?CacheItemPoolInterface
{
if (self::$_metadataCacheImpl === null) {
self::$_metadataCacheImpl = new ArrayCache();
if (self::$_metadataCache === null) {
self::$_metadataCache = new ArrayAdapter();
}
return self::$_metadataCacheImpl;
return self::$_metadataCache;
}
private static function getSharedQueryCacheImpl(): Cache