Skip to content

Commit

Permalink
Merge branch 'feature/#954-multi-get-slc-regions'
Browse files Browse the repository at this point in the history
Close #954
  • Loading branch information
Ocramius committed Jan 17, 2015
2 parents 8f097ab + d5f6b44 commit 4cde35d
Show file tree
Hide file tree
Showing 22 changed files with 362 additions and 50 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"doctrine/dbal": ">=2.5-dev,<2.6-dev",
"doctrine/instantiator": "~1.0.1",
"doctrine/common": ">=2.5-dev,<2.6-dev",
"doctrine/cache": "~1.4",
"symfony/console": "~2.5"
},
"require-dev": {
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 @@ -185,7 +185,7 @@ To enable the second-level-cache, you should provide a cache factory
<?php
/* var $config \Doctrine\ORM\Cache\RegionsConfiguration */
/* var $cache \Doctrine\Common\Cache\CacheProvider */
/* var $cache \Doctrine\Common\Cache\Cache */
$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($config, $cache);
Expand Down
8 changes: 5 additions & 3 deletions lib/Doctrine/ORM/Cache/CollectionCacheEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ class CollectionCacheEntry implements CacheEntry
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
*
* @var array The list of entity identifiers hold by the collection
* @var CacheKey[] The list of entity identifiers hold by the collection
*/
public $identifiers;

/**
* @param array $identifiers List of entity identifiers hold by the collection
* @param CacheKey[] $identifiers List of entity identifiers hold by the collection
*/
public function __construct(array $identifiers)
{
Expand All @@ -46,9 +46,11 @@ public function __construct(array $identifiers)
/**
* Creates a new CollectionCacheEntry
*
* This method allow Doctrine\Common\Cache\PhpFileCache compatibility
* This method allows for Doctrine\Common\Cache\PhpFileCache compatibility
*
* @param array $values array containing property values
*
* @return self
*/
public static function __set_state(array $values)
{
Expand Down
49 changes: 32 additions & 17 deletions lib/Doctrine/ORM/Cache/DefaultCacheFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,25 @@

namespace Doctrine\ORM\Cache;

use Doctrine\Common\Cache\Cache as CacheAdapter;
use Doctrine\Common\Cache\CacheProvider;

use Doctrine\Common\Cache\MultiGetCache;
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;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion;
use Doctrine\ORM\Cache\Region\DefaultRegion;
use Doctrine\ORM\Cache\Region\FileLockRegion;
use Doctrine\ORM\Cache\Region\UpdateTimestampCache;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister;
use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister;
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\Collection\NonStrictReadWriteCachedCollectionPersister;
use Doctrine\ORM\Persisters\Entity\EntityPersister;

/**
* @since 2.5
Expand All @@ -45,7 +47,7 @@
class DefaultCacheFactory implements CacheFactory
{
/**
* @var \Doctrine\Common\Cache\CacheProvider
* @var CacheAdapter
*/
private $cache;

Expand All @@ -70,10 +72,10 @@ class DefaultCacheFactory implements CacheFactory
private $fileLockRegionDirectory;

/**
* @param \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig
* @param \Doctrine\Common\Cache\CacheProvider $cache
* @param RegionsConfiguration $cacheConfig
* @param CacheAdapter $cache
*/
public function __construct(RegionsConfiguration $cacheConfig, CacheProvider $cache)
public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
{
$this->cache = $cache;
$this->regionsConfig = $cacheConfig;
Expand Down Expand Up @@ -178,7 +180,13 @@ public function buildQueryCache(EntityManagerInterface $em, $regionName = null)
*/
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping)
{
return new DefaultCollectionHydrator($em);
/* @var $targetPersister \Doctrine\ORM\Cache\Persister\CachedPersister */
$targetPersister = $em->getUnitOfWork()->getEntityPersister($mapping['targetEntity']);

return new DefaultCollectionHydrator(
$em,
$targetPersister->getCacheRegion()
);
}

/**
Expand All @@ -200,9 +208,16 @@ public function getRegion(array $cache)

$cacheAdapter = clone $this->cache;

$cacheAdapter->setNamespace($cache['region']);
if ($cacheAdapter instanceof CacheProvider) {
$cacheAdapter->setNamespace($cache['region']);
}

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

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

if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {

Expand Down
18 changes: 9 additions & 9 deletions lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key
$data = array();

foreach ($collection as $index => $entity) {
$data[$index] = $this->uow->getEntityIdentifier($entity);
$data[$index] = new EntityCacheKey($metadata->name, $this->uow->getEntityIdentifier($entity));
}

return new CollectionCacheEntry($data);
}

Expand All @@ -77,19 +76,20 @@ public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
{
$assoc = $metadata->associationMappings[$key->association];
/* @var $targetPersister \Doctrine\ORM\Cache\Persister\CachedPersister */
$targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
$targetRegion = $targetPersister->getCacheRegion();
$list = array();

foreach ($entry->identifiers as $index => $identifier) {

$entityEntry = $targetRegion->get(new EntityCacheKey($assoc['targetEntity'], $identifier));
$entityEntries = $targetRegion->getMultiple($entry);

if ($entityEntry === null) {
return null;
}
if ($entityEntries === null) {
return null;
}

$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
/* @var $entityEntries \Doctrine\ORM\Cache\EntityCacheEntry[] */
foreach ($entityEntries as $index => $entityEntry) {
$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->data, self::$hints);
}

array_walk($list, function($entity, $index) use ($collection) {
Expand Down
42 changes: 42 additions & 0 deletions lib/Doctrine/ORM/Cache/MultiGetRegion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\ORM\Cache;

/**
* Defines a region that supports multi-get reading.
*
* With one method call we can get multipe items.
*
* @since 2.5
* @author Asmir Mustafic
*/
interface MultiGetRegion
{
/**
* Get all items from the cache indentifed by $keys.
* It returns NULL if some elements can not be found.
*
* @param CollectionCacheEntry $collection The collection of the items to be retrieved.
*
* @return CacheEntry[]|null The cached entries or NULL if one or more entries can not be found
*/
public function getMultiple(CollectionCacheEntry $collection);
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ public function storeCollectionCache(CollectionCacheKey $key, $elements)
$targetHydrator = $targetPersister->getEntityHydrator();
$entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements);

foreach ($entry->identifiers as $index => $identifier) {
$entityKey = new EntityCacheKey($this->targetEntity->rootEntityName, $identifier);
foreach ($entry->identifiers as $index => $entityKey) {

if ($targetRegion->contains($entityKey)) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/ORM/Cache/Region.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* @since 2.5
* @author Fabio B. Silva <[email protected]>
*/
interface Region
interface Region extends MultiGetRegion
{
/**
* Retrieve the name of this region.
Expand Down
75 changes: 75 additions & 0 deletions lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\ORM\Cache\Region;

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

/**
* A cache region that enables the retrieval of multiple elements with one call
*
* @since 2.5
* @author Asmir Mustafic <[email protected]>
*/
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|\Doctrine\Common\Cache\Cache
*/
protected $cache;

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

/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
$keysToRetrieve = array();
foreach ($collection->identifiers as $index => $key) {
$keysToRetrieve[$index] = $this->name . '_' . $key->hash;
}

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

$returnableItems = array();
foreach ($keysToRetrieve as $index => $key) {
$returnableItems[$index] = $items[$key];
}
return $returnableItems;
}
}
Loading

0 comments on commit 4cde35d

Please sign in to comment.