Skip to content

Commit

Permalink
Merge pull request #9322 from derrabus/feature/psr-region-cache
Browse files Browse the repository at this point in the history
PSR-6 second level cache
  • Loading branch information
greg0ire authored Jan 9, 2022
2 parents c6d8aec + 5d0fbc4 commit 0d911b9
Show file tree
Hide file tree
Showing 25 changed files with 304 additions and 408 deletions.
16 changes: 16 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Upgrade to 2.11

## PSR-6-based second level cache

The second level cache has been reworked to consume a PSR-6 cache. Using a
Doctrine Cache instance is deprecated.

* `DefaultCacheFactory`: The constructor expects a PSR-6 cache item pool as
second argument now.
* `DefaultMultiGetRegion`: This class is deprecated in favor of `DefaultRegion`.
* `DefaultRegion`:
* The constructor expects a PSR-6 cache item pool as second argument now.
* The protected `$cache` property is deprecated.
* The properties `$name` and `$lifetime` as well as the constant
`REGION_KEY_SEPARATOR` and the method `getCacheEntryKey()` are flagged as
`@internal` now. They all will become `private` in 3.0.
* The method `getCache()` is deprecated without replacement.

## Deprecated: `Doctrine\ORM\Mapping\Driver\PHPDriver`

Use `StaticPHPDriver` instead when you want to programmatically configure
Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/second-level-cache.rst
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ To enable the second-level-cache, you should provide a cache factory.
<?php
/** @var \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig */
/** @var \Doctrine\Common\Cache\Cache $cache */
/** @var \Psr\Cache\CacheItemPoolInterface $cache */
/** @var \Doctrine\ORM\Configuration $config */
$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($cacheConfig, $cache);
Expand Down
77 changes: 40 additions & 37 deletions lib/Doctrine/ORM/Cache/DefaultCacheFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@

namespace Doctrine\ORM\Cache;

use Doctrine\Common\Cache\Cache as CacheAdapter;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\MultiGetCache;
use Doctrine\Common\Cache\Cache as LegacyCache;
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister;
use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister;
use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister;
use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion;
use Doctrine\ORM\Cache\Region\DefaultRegion;
use Doctrine\ORM\Cache\Region\FileLockRegion;
use Doctrine\ORM\Cache\Region\UpdateTimestampCache;
Expand All @@ -24,16 +23,19 @@
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use InvalidArgumentException;
use LogicException;
use Psr\Cache\CacheItemPoolInterface;
use TypeError;

use function assert;
use function get_debug_type;
use function sprintf;

use const DIRECTORY_SEPARATOR;

class DefaultCacheFactory implements CacheFactory
{
/** @var CacheAdapter */
private $cache;
/** @var CacheItemPoolInterface */
private $cacheItemPool;

/** @var RegionsConfiguration */
private $regionsConfig;
Expand All @@ -47,9 +49,33 @@ class DefaultCacheFactory implements CacheFactory
/** @var string|null */
private $fileLockRegionDirectory;

public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
/**
* @param CacheItemPoolInterface $cacheItemPool
*/
public function __construct(RegionsConfiguration $cacheConfig, $cacheItemPool)
{
$this->cache = $cache;
if ($cacheItemPool instanceof LegacyCache) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/9322',
'Passing an instance of %s to %s is deprecated, pass a %s instead.',
get_debug_type($cacheItemPool),
__METHOD__,
CacheItemPoolInterface::class
);

$this->cacheItemPool = CacheAdapter::wrap($cacheItemPool);
} elseif (! $cacheItemPool instanceof CacheItemPoolInterface) {
throw new TypeError(sprintf(
'%s: Parameter #2 is expected to be an instance of %s, got %s.',
__METHOD__,
CacheItemPoolInterface::class,
get_debug_type($cacheItemPool)
));
} else {
$this->cacheItemPool = $cacheItemPool;
}

$this->regionsConfig = $cacheConfig;
}

Expand Down Expand Up @@ -183,13 +209,9 @@ public function getRegion(array $cache)
return $this->regions[$cache['region']];
}

$name = $cache['region'];
$cacheAdapter = $this->createRegionCache($name);
$lifetime = $this->regionsConfig->getLifetime($cache['region']);

$region = $cacheAdapter instanceof MultiGetCache
? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
: new DefaultRegion($name, $cacheAdapter, $lifetime);
$name = $cache['region'];
$lifetime = $this->regionsConfig->getLifetime($cache['region']);
$region = new DefaultRegion($name, $this->cacheItemPool, $lifetime);

if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
if (
Expand All @@ -209,25 +231,6 @@ public function getRegion(array $cache)
return $this->regions[$cache['region']] = $region;
}

private function createRegionCache(string $name): CacheAdapter
{
$cacheAdapter = clone $this->cache;

if (! $cacheAdapter instanceof CacheProvider) {
return $cacheAdapter;
}

$namespace = $cacheAdapter->getNamespace();

if ($namespace !== '') {
$namespace .= ':';
}

$cacheAdapter->setNamespace($namespace . $name);

return $cacheAdapter;
}

/**
* {@inheritdoc}
*/
Expand All @@ -237,7 +240,7 @@ public function getTimestampRegion()
$name = Cache::DEFAULT_TIMESTAMP_REGION_NAME;
$lifetime = $this->regionsConfig->getLifetime($name);

$this->timestampRegion = new UpdateTimestampCache($name, clone $this->cache, $lifetime);
$this->timestampRegion = new UpdateTimestampCache($name, $this->cacheItemPool, $lifetime);
}

return $this->timestampRegion;
Expand All @@ -246,8 +249,8 @@ public function getTimestampRegion()
/**
* {@inheritdoc}
*/
public function createCache(EntityManagerInterface $em)
public function createCache(EntityManagerInterface $entityManager)
{
return new DefaultCache($em);
return new DefaultCache($entityManager);
}
}
57 changes: 2 additions & 55 deletions lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,11 @@

namespace Doctrine\ORM\Cache\Region;

use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\MultiGetCache;
use Doctrine\ORM\Cache\CacheEntry;
use Doctrine\ORM\Cache\CollectionCacheEntry;

use function assert;
use function count;

/**
* A cache region that enables the retrieval of multiple elements with one call
*
* @deprecated Use {@link DefaultRegion} instead.
*/
class DefaultMultiGetRegion extends DefaultRegion
{
/**
* Note that the multiple type is due to doctrine/cache not integrating the MultiGetCache interface
* in its signature due to BC in 1.x
*
* @var MultiGetCache|Cache
*/
protected $cache;

/**
* {@inheritDoc}
*
* @param MultiGetCache $cache
*/
public function __construct($name, MultiGetCache $cache, $lifetime = 0)
{
assert($cache instanceof Cache);
parent::__construct($name, $cache, $lifetime);
}

/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
$keysToRetrieve = [];

foreach ($collection->identifiers as $index => $key) {
$keysToRetrieve[$index] = $this->getCacheEntryKey($key);
}

$items = $this->cache->fetchMultiple($keysToRetrieve);
if (count($items) !== count($keysToRetrieve)) {
return null;
}

$returnableItems = [];

foreach ($keysToRetrieve as $index => $key) {
if (! $items[$key] instanceof CacheEntry) {
return null;
}

$returnableItems[$index] = $items[$key];
}

return $returnableItems;
}
}
Loading

0 comments on commit 0d911b9

Please sign in to comment.