1
0
mirror of synced 2025-01-19 15:01:40 +03:00

Merge branch 'feature/#954-multi-get-slc-regions'

Close #954
This commit is contained in:
Marco Pivetta 2015-01-17 23:49:40 +01:00
commit 4cde35dc18
22 changed files with 364 additions and 52 deletions

View File

@ -19,6 +19,7 @@
"doctrine/dbal": ">=2.5-dev,<2.6-dev", "doctrine/dbal": ">=2.5-dev,<2.6-dev",
"doctrine/instantiator": "~1.0.1", "doctrine/instantiator": "~1.0.1",
"doctrine/common": ">=2.5-dev,<2.6-dev", "doctrine/common": ">=2.5-dev,<2.6-dev",
"doctrine/cache": "~1.4",
"symfony/console": "~2.5" "symfony/console": "~2.5"
}, },
"require-dev": { "require-dev": {

View File

@ -185,7 +185,7 @@ To enable the second-level-cache, you should provide a cache factory
<?php <?php
/* var $config \Doctrine\ORM\Cache\RegionsConfiguration */ /* 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); $factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($config, $cache);

View File

@ -31,12 +31,12 @@ class CollectionCacheEntry implements CacheEntry
/** /**
* READ-ONLY: Public only for performance reasons, it should be considered immutable. * 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; 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) public function __construct(array $identifiers)
{ {
@ -46,9 +46,11 @@ class CollectionCacheEntry implements CacheEntry
/** /**
* Creates a new CollectionCacheEntry * 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 * @param array $values array containing property values
*
* @return self
*/ */
public static function __set_state(array $values) public static function __set_state(array $values)
{ {

View File

@ -20,23 +20,25 @@
namespace Doctrine\ORM\Cache; namespace Doctrine\ORM\Cache;
use Doctrine\Common\Cache\Cache as CacheAdapter;
use Doctrine\Common\Cache\CacheProvider; use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\MultiGetCache;
use Doctrine\ORM\Cache; use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\EntityManagerInterface;
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\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\ReadOnlyCachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister; use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister;
use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister;
use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister; use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister;
use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister;
use Doctrine\ORM\Cache\Region;
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\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
/** /**
* @since 2.5 * @since 2.5
@ -45,7 +47,7 @@ use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPe
class DefaultCacheFactory implements CacheFactory class DefaultCacheFactory implements CacheFactory
{ {
/** /**
* @var \Doctrine\Common\Cache\CacheProvider * @var CacheAdapter
*/ */
private $cache; private $cache;
@ -70,10 +72,10 @@ class DefaultCacheFactory implements CacheFactory
private $fileLockRegionDirectory; private $fileLockRegionDirectory;
/** /**
* @param \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig * @param RegionsConfiguration $cacheConfig
* @param \Doctrine\Common\Cache\CacheProvider $cache * @param CacheAdapter $cache
*/ */
public function __construct(RegionsConfiguration $cacheConfig, CacheProvider $cache) public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
{ {
$this->cache = $cache; $this->cache = $cache;
$this->regionsConfig = $cacheConfig; $this->regionsConfig = $cacheConfig;
@ -178,7 +180,13 @@ class DefaultCacheFactory implements CacheFactory
*/ */
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping) 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()
);
} }
/** /**
@ -200,9 +208,16 @@ class DefaultCacheFactory implements CacheFactory
$cacheAdapter = clone $this->cache; $cacheAdapter = clone $this->cache;
$cacheAdapter->setNamespace($cache['region']); if ($cacheAdapter instanceof CacheProvider) {
$cacheAdapter->setNamespace($cache['region']);
}
$region = new DefaultRegion($cache['region'], $cacheAdapter, $this->regionsConfig->getLifetime($cache['region'])); $name = $cache['region'];
$lifetime = $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) { if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {

View File

@ -65,9 +65,8 @@ class DefaultCollectionHydrator implements CollectionHydrator
$data = array(); $data = array();
foreach ($collection as $index => $entity) { 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); return new CollectionCacheEntry($data);
} }
@ -77,19 +76,20 @@ class DefaultCollectionHydrator implements CollectionHydrator
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection) public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
{ {
$assoc = $metadata->associationMappings[$key->association]; $assoc = $metadata->associationMappings[$key->association];
/* @var $targetPersister \Doctrine\ORM\Cache\Persister\CachedPersister */
$targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']); $targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
$targetRegion = $targetPersister->getCacheRegion(); $targetRegion = $targetPersister->getCacheRegion();
$list = array(); $list = array();
foreach ($entry->identifiers as $index => $identifier) { $entityEntries = $targetRegion->getMultiple($entry);
$entityEntry = $targetRegion->get(new EntityCacheKey($assoc['targetEntity'], $identifier)); if ($entityEntries === null) {
return null;
}
if ($entityEntry === null) { /* @var $entityEntries \Doctrine\ORM\Cache\EntityCacheEntry[] */
return null; foreach ($entityEntries as $index => $entityEntry) {
} $list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->data, self::$hints);
$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
} }
array_walk($list, function($entity, $index) use ($collection) { array_walk($list, function($entity, $index) use ($collection) {

View File

@ -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);
}

View File

@ -167,8 +167,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
$targetHydrator = $targetPersister->getEntityHydrator(); $targetHydrator = $targetPersister->getEntityHydrator();
$entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements);
foreach ($entry->identifiers as $index => $identifier) { foreach ($entry->identifiers as $index => $entityKey) {
$entityKey = new EntityCacheKey($this->targetEntity->rootEntityName, $identifier);
if ($targetRegion->contains($entityKey)) { if ($targetRegion->contains($entityKey)) {
continue; continue;

View File

@ -26,7 +26,7 @@ namespace Doctrine\ORM\Cache;
* @since 2.5 * @since 2.5
* @author Fabio B. Silva <fabio.bat.silva@gmail.com> * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/ */
interface Region interface Region extends MultiGetRegion
{ {
/** /**
* Retrieve the name of this region. * Retrieve the name of this region.

View File

@ -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 <goetas@gmail.com>
*/
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;
}
}

View File

@ -20,11 +20,13 @@
namespace Doctrine\ORM\Cache\Region; namespace Doctrine\ORM\Cache\Region;
use Doctrine\Common\Cache\Cache as CacheAdapter;
use Doctrine\Common\Cache\ClearableCache;
use Doctrine\ORM\Cache\CacheEntry;
use Doctrine\ORM\Cache\CacheKey;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\Lock; use Doctrine\ORM\Cache\Lock;
use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\CacheKey;
use Doctrine\ORM\Cache\CacheEntry;
use Doctrine\Common\Cache\CacheProvider;
/** /**
* The simplest cache region compatible with all doctrine-cache drivers. * The simplest cache region compatible with all doctrine-cache drivers.
@ -35,7 +37,7 @@ use Doctrine\Common\Cache\CacheProvider;
class DefaultRegion implements Region class DefaultRegion implements Region
{ {
/** /**
* @var \Doctrine\Common\Cache\CacheProvider * @var CacheAdapter
*/ */
protected $cache; protected $cache;
@ -50,11 +52,11 @@ class DefaultRegion implements Region
protected $lifetime = 0; protected $lifetime = 0;
/** /**
* @param string $name * @param string $name
* @param \Doctrine\Common\Cache\CacheProvider $cache * @param CacheAdapter $cache
* @param integer $lifetime * @param integer $lifetime
*/ */
public function __construct($name, CacheProvider $cache, $lifetime = 0) public function __construct($name, CacheAdapter $cache, $lifetime = 0)
{ {
$this->cache = $cache; $this->cache = $cache;
$this->name = (string) $name; $this->name = (string) $name;
@ -93,6 +95,37 @@ class DefaultRegion implements Region
return $this->cache->fetch($this->name . '_' . $key->hash) ?: null; return $this->cache->fetch($this->name . '_' . $key->hash) ?: null;
} }
/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
$keysToRetrieve = array();
foreach ($collection->identifiers as $index => $key) {
$keysToRetrieve[$index] = $this->name . '_' . $key->hash;
}
$items = array_filter(
array_map([$this->cache, 'fetch'], $keysToRetrieve),
function ($retrieved) {
return false !== $retrieved;
}
);
if (count($items) !== count($keysToRetrieve)) {
return null;
}
$returnableItems = array();
foreach ($keysToRetrieve as $index => $key) {
$returnableItems[$index] = $items[$key];
}
return $returnableItems;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -114,6 +147,13 @@ class DefaultRegion implements Region
*/ */
public function evictAll() public function evictAll()
{ {
if (! $this->cache instanceof ClearableCache) {
throw new \BadMethodCallException(sprintf(
'Clearing all cache entries is not supported by the supplied cache adapter of type %s',
get_class($this->cache)
));
}
return $this->cache->deleteAll(); return $this->cache->deleteAll();
} }
} }

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Cache\Region; namespace Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\Lock; use Doctrine\ORM\Cache\Lock;
use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\CacheKey;
@ -172,6 +173,18 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->get($key); return $this->region->get($key);
} }
/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
if (array_filter(array_map([$this, 'isLocked'], $collection->identifiers))) {
return null;
}
return $this->region->getMultiple($collection);
}
/** /**
* {inheritdoc} * {inheritdoc}
*/ */

View File

@ -4,6 +4,7 @@ namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Cache\CacheEntry; use Doctrine\ORM\Cache\CacheEntry;
use Doctrine\ORM\Cache\CacheKey; use Doctrine\ORM\Cache\CacheKey;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\Lock; use Doctrine\ORM\Cache\Lock;
use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\Region;
@ -94,6 +95,16 @@ class CacheRegionMock implements Region
return $this->getReturn(__FUNCTION__, null); return $this->getReturn(__FUNCTION__, null);
} }
/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
$this->calls[__FUNCTION__][] = array('collection' => $collection);
return $this->getReturn(__FUNCTION__, null);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -3,6 +3,7 @@
namespace Doctrine\Tests\Mocks; namespace Doctrine\Tests\Mocks;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\ConcurrentRegion; use Doctrine\ORM\Cache\ConcurrentRegion;
use Doctrine\ORM\Cache\LockException; use Doctrine\ORM\Cache\LockException;
use Doctrine\ORM\Cache\CacheEntry; use Doctrine\ORM\Cache\CacheEntry;
@ -131,6 +132,18 @@ class ConcurrentRegionMock implements ConcurrentRegion
return $this->region->get($key); return $this->region->get($key);
} }
/**
* {@inheritdoc}
*/
public function getMultiple(CollectionCacheEntry $collection)
{
$this->calls[__FUNCTION__][] = array('collection' => $collection);
$this->throwException(__FUNCTION__);
return $this->region->getMultiple($collection);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -64,7 +64,6 @@ class DefaultCacheFactoryTest extends OrmTestCase
->with($this->equalTo($metadata->cache)) ->with($this->equalTo($metadata->cache))
->will($this->returnValue($region)); ->will($this->returnValue($region));
$cachedPersister = $this->factory->buildCachedEntityPersister($em, $persister, $metadata); $cachedPersister = $this->factory->buildCachedEntityPersister($em, $persister, $metadata);
$this->assertInstanceOf('Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister', $cachedPersister); $this->assertInstanceOf('Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister', $cachedPersister);
@ -281,4 +280,37 @@ class DefaultCacheFactoryTest extends OrmTestCase
$this->assertSame('foo', $fooRegion->getCache()->getNamespace()); $this->assertSame('foo', $fooRegion->getCache()->getNamespace());
$this->assertSame('bar', $barRegion->getCache()->getNamespace()); $this->assertSame('bar', $barRegion->getCache()->getNamespace());
} }
public function testBuildsDefaultCacheRegionFromGenericCacheRegion()
{
/* @var $cache \Doctrine\Common\Cache\Cache */
$cache = $this->getMock('Doctrine\Common\Cache\Cache');
$factory = new DefaultCacheFactory($this->regionsConfig, $cache);
$this->assertInstanceOf(
'Doctrine\ORM\Cache\Region\DefaultRegion',
$factory->getRegion(array(
'region' => 'bar',
'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY,
))
);
}
public function testBuildsMultiGetCacheRegionFromGenericCacheRegion()
{
/* @var $cache \Doctrine\Common\Cache\CacheProvider */
$cache = $this->getMockForAbstractClass('Doctrine\Common\Cache\CacheProvider');
$factory = new DefaultCacheFactory($this->regionsConfig, $cache);
$this->assertInstanceOf(
'Doctrine\ORM\Cache\Region\DefaultMultiGetRegion',
$factory->getRegion(array(
'region' => 'bar',
'usage' => ClassMetadata::CACHE_USAGE_READ_ONLY,
))
);
}
} }

View File

@ -29,7 +29,8 @@ class DefaultCollectionHydratorTest extends OrmFunctionalTestCase
$this->enableSecondLevelCache(); $this->enableSecondLevelCache();
parent::setUp(); parent::setUp();
$this->structure = new DefaultCollectionHydrator($this->_em); $targetPersister = $this->_em->getUnitOfWork()->getEntityPersister(City::CLASSNAME);
$this->structure = new DefaultCollectionHydrator($this->_em, $targetPersister);
} }
public function testImplementsCollectionEntryStructure() public function testImplementsCollectionEntryStructure()
@ -41,8 +42,8 @@ class DefaultCollectionHydratorTest extends OrmFunctionalTestCase
{ {
$targetRegion = $this->_em->getCache()->getEntityCacheRegion(City::CLASSNAME); $targetRegion = $this->_em->getCache()->getEntityCacheRegion(City::CLASSNAME);
$entry = new CollectionCacheEntry(array( $entry = new CollectionCacheEntry(array(
array('id'=>31), new EntityCacheKey(City::CLASSNAME, array('id'=>31)),
array('id'=>32), new EntityCacheKey(City::CLASSNAME, array('id'=>32)),
)); ));
$targetRegion->put(new EntityCacheKey(City::CLASSNAME, array('id'=>31)), new EntityCacheEntry(City::CLASSNAME, array('id'=>31, 'name'=>'Foo'))); $targetRegion->put(new EntityCacheKey(City::CLASSNAME, array('id'=>31)), new EntityCacheEntry(City::CLASSNAME, array('id'=>31, 'name'=>'Foo')));

View File

@ -60,4 +60,16 @@ class DefaultRegionTest extends AbstractRegionTest
$this->assertSame('foo', $cache->getNamespace()); $this->assertSame('foo', $cache->getNamespace());
} }
public function testEvictAllWithGenericCacheThrowsUnsupportedException()
{
/* @var $cache \Doctrine\Common\Cache\Cache */
$cache = $this->getMock('Doctrine\Common\Cache\Cache');
$region = new DefaultRegion('foo', $cache);
$this->setExpectedException('BadMethodCallException');
$region->evictAll();
}
} }

View File

@ -0,0 +1,41 @@
<?php
namespace Doctrine\Tests\ORM\Cache;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Tests\Mocks\CacheEntryMock;
use Doctrine\Tests\Mocks\CacheKeyMock;
use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\EntityCacheKey;
/**
* @author Asmir Mustafic <goetas@gmail.com>
*/
class MultiGetRegionTest extends AbstractRegionTest
{
protected function createRegion()
{
return new DefaultMultiGetRegion('default.region.test', $this->cache);
}
public function testGetMulti()
{
$key1 = new CacheKeyMock('key.1');
$value1 = new CacheEntryMock(array('id'=>1, 'name' => 'bar'));
$key2 = new CacheKeyMock('key.2');
$value2 = new CacheEntryMock(array('id'=>2, 'name' => 'bar'));
$this->assertFalse($this->region->contains($key1));
$this->assertFalse($this->region->contains($key2));
$this->region->put($key1, $value1);
$this->region->put($key2, $value2);
$actual = $this->region->getMultiple(new CollectionCacheEntry(array($key1, $key2)));
$this->assertEquals($value1, $actual[0]);
$this->assertEquals($value2, $actual[1]);
}
}

View File

@ -38,6 +38,7 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase
'getName', 'getName',
'contains', 'contains',
'get', 'get',
'getMultiple',
'put', 'put',
'evict', 'evict',
'evictAll' 'evictAll'
@ -56,6 +57,7 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase
'removeElement', 'removeElement',
'removeKey', 'removeKey',
'get', 'get',
'getMultiple',
'loadCriteria' 'loadCriteria'
); );
@ -65,7 +67,7 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase
* @param \Doctrine\ORM\Cache\Region $region * @param \Doctrine\ORM\Cache\Region $region
* @param array $mapping * @param array $mapping
* *
* @return Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister * @return \Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister
*/ */
abstract protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping); abstract protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping);
@ -77,7 +79,10 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase
$this->em = $this->_getTestEntityManager(); $this->em = $this->_getTestEntityManager();
$this->region = $this->createRegion(); $this->region = $this->createRegion();
$this->collectionPersister = $this->getMock('Doctrine\ORM\Persisters\Collection\CollectionPersister', $this->collectionPersisterMockMethods); $this->collectionPersister = $this->getMock(
'Doctrine\ORM\Persisters\Collection\CollectionPersister',
$this->collectionPersisterMockMethods
);
} }
/** /**

View File

@ -19,6 +19,7 @@ class ReadWriteCachedCollectionPersisterTest extends AbstractCollectionPersister
'getName', 'getName',
'contains', 'contains',
'get', 'get',
'getMultiple',
'put', 'put',
'evict', 'evict',
'evictAll', 'evictAll',

View File

@ -41,6 +41,7 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase
'getName', 'getName',
'contains', 'contains',
'get', 'get',
'getMultiple',
'put', 'put',
'evict', 'evict',
'evictAll' 'evictAll'
@ -85,7 +86,7 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase
* @param \Doctrine\ORM\Cache\Region $region * @param \Doctrine\ORM\Cache\Region $region
* @param \Doctrine\ORM\Mapping\ClassMetadata $metadata * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata
* *
* @return Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister * @return \Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister
*/ */
abstract protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata); abstract protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata);
@ -97,7 +98,10 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase
$this->em = $this->_getTestEntityManager(); $this->em = $this->_getTestEntityManager();
$this->region = $this->createRegion(); $this->region = $this->createRegion();
$this->entityPersister = $this->getMock('Doctrine\ORM\Persisters\Entity\EntityPersister', $this->entityPersisterMockMethods); $this->entityPersister = $this->getMock(
'Doctrine\ORM\Persisters\Entity\EntityPersister',
$this->entityPersisterMockMethods
);
} }
/** /**
@ -109,7 +113,7 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase
} }
/** /**
* @return Doctrine\ORM\Cache\Persister\AbstractEntityPersister * @return \Doctrine\ORM\Cache\Persister\AbstractEntityPersister
*/ */
protected function createPersisterDefault() protected function createPersisterDefault()
{ {

View File

@ -20,6 +20,7 @@ class ReadWriteCachedEntityPersisterTest extends AbstractEntityPersisterTest
'getName', 'getName',
'contains', 'contains',
'get', 'get',
'getMultiple',
'put', 'put',
'evict', 'evict',
'evictAll', 'evictAll',

View File

@ -39,6 +39,10 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; $class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$class->associationMappings['phonenumbers']['indexBy'] = 'phonenumber'; $class->associationMappings['phonenumbers']['indexBy'] = 'phonenumber';
unset($class->associationMappings['phonenumbers']['cache']);
unset($class->associationMappings['articles']['cache']);
unset($class->associationMappings['users']['cache']);
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$class->associationMappings['users']['indexBy'] = 'username'; $class->associationMappings['users']['indexBy'] = 'username';