From 61bff7d5f63490c2ac0fd882e3cec88c2673e9b0 Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Mon, 7 Oct 2013 18:53:32 -0400 Subject: [PATCH] Fix CS and update docs --- docs/en/reference/annotations-reference.rst | 12 ++ docs/en/reference/second-level-cache.rst | 128 +++++++++++++++--- lib/Doctrine/ORM/AbstractQuery.php | 50 ++++--- lib/Doctrine/ORM/Cache.php | 4 +- lib/Doctrine/ORM/Cache/CacheConfiguration.php | 6 +- lib/Doctrine/ORM/Cache/CacheEntry.php | 4 + lib/Doctrine/ORM/Cache/CacheFactory.php | 2 + lib/Doctrine/ORM/Cache/CollectionHydrator.php | 4 +- lib/Doctrine/ORM/Cache/DefaultCache.php | 14 +- .../ORM/Cache/DefaultCacheFactory.php | 13 +- lib/Doctrine/ORM/Cache/DefaultQueryCache.php | 22 ++- lib/Doctrine/ORM/Cache/EntityHydrator.php | 2 +- .../Persister/AbstractCollectionPersister.php | 5 +- .../Persister/AbstractEntityPersister.php | 40 +++--- ...rictReadWriteCachedCollectionPersister.php | 1 - ...onStrictReadWriteCachedEntityPersister.php | 2 - .../ReadWriteCachedCollectionPersister.php | 5 - .../ReadWriteCachedEntityPersister.php | 5 - lib/Doctrine/ORM/Cache/QueryCache.php | 12 +- lib/Doctrine/ORM/Cache/QueryCacheKey.php | 4 +- .../ORM/Cache/Region/DefaultRegion.php | 10 +- .../ORM/Cache/Region/FileLockRegion.php | 16 +-- .../ORM/Cache/RegionsConfiguration.php | 16 +-- .../ORM/Cache/TimestampCacheEntry.php | 4 +- lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 32 +++-- .../ORM/Mapping/Driver/YamlDriver.php | 12 +- lib/Doctrine/ORM/ORMException.php | 2 +- .../ORM/Persisters/CollectionPersister.php | 2 - .../ORM/Persisters/EntityPersister.php | 1 - lib/Doctrine/ORM/Query.php | 2 +- lib/Doctrine/ORM/Query/ResultSetMapping.php | 8 ++ lib/Doctrine/ORM/Query/SqlWalker.php | 2 + lib/Doctrine/ORM/UnitOfWork.php | 10 +- .../EventListener/CacheMetadataListener.php | 2 +- .../Doctrine/Tests/Mocks/CacheRegionMock.php | 4 +- .../Tests/Mocks/ConcurrentRegionMock.php | 2 +- .../ORM/Cache/DefaultCacheFactoryTest.php | 2 +- .../Tests/ORM/Cache/DefaultQueryCacheTest.php | 28 +++- .../Tests/ORM/Cache/FileLockRegionTest.php | 1 - .../SecondLevelCacheAbstractTest.php | 2 - ...condLevelCacheCompositePrimaryKeyTest.php} | 3 +- ...econdLevelCacheExtraLazyCollectionTest.php | 1 - ...condLevelCacheJoinTableInheritanceTest.php | 1 - .../SecondLevelCacheOneToManyTest.php | 1 - .../SecondLevelCacheQueryCacheTest.php | 23 ++++ .../ORM/Performance/SecondLevelCacheTest.php | 2 - tests/Doctrine/Tests/OrmTestCase.php | 1 - 47 files changed, 338 insertions(+), 187 deletions(-) rename tests/Doctrine/Tests/ORM/Functional/{SecondLevelCacheCompositPrimaryKeyTest.php => SecondLevelCacheCompositePrimaryKeyTest.php} (98%) diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 2ebc5c1f8..62869297f 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -35,6 +35,7 @@ Index - :ref:`@Column ` - :ref:`@ColumnResult ` +- :ref:`@Cache ` - :ref:`@ChangeTrackingPolicy ` - :ref:`@DiscriminatorColumn ` - :ref:`@DiscriminatorMap ` @@ -152,6 +153,17 @@ Required attributes: - **name**: The name of a column in the SELECT clause of a SQL query +.. _annref_cache: + +@Cache +~~~~~~~~~~~~~~ +Add caching strategy to a root entity or a collection. + +Optional attributes: + +- **usage**: One of ``READ_ONLY``, ``READ_READ_WRITE`` or ``NONSTRICT_READ_WRITE``, By default this is ``READ_ONLY``. +- **region**: An specific region name + .. _annref_changetrackingpolicy: @ChangeTrackingPolicy diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index 7139a1c38..193a563f1 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -155,7 +155,7 @@ Defines contract for concurrently managed data region. * * @return \Doctrine\ORM\Cache\Lock A lock instance or NULL if the lock already exists. */ - public function readLock(CacheKey $key); + public function lock(CacheKey $key); /** * Attempts to read unlock the mapping for the given key. @@ -163,9 +163,31 @@ Defines contract for concurrently managed data region. * @param \Doctrine\ORM\Cache\CacheKey $key The key of the item to unlock. * @param \Doctrine\ORM\Cache\Lock $lock The lock previously obtained from readLock */ - public function readUnlock(CacheKey $key, Lock $lock); + public function unlock(CacheKey $key, Lock $lock); } +``Doctrine\ORM\Cache\TimestampRegion`` + +Tracks the timestamps of the most recent updates to particular entity. + +.. code-block:: php + + setSecondLevelCacheEnabled(); //Cache factory - $config->setSecondLevelCacheFactory($factory); + $config->getSecondLevelCacheConfiguration() + ->setCacheFactory($factory); Cache Factory @@ -290,22 +313,22 @@ It allows you to provide a specific implementation of the following components : public function buildQueryCache(EntityManagerInterface $em, $regionName = null); /** - * Build an entity hidrator + * Build an entity hydrator * * @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager. * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The entity metadata. * - * @return \Doctrine\ORM\Cache\EntityHydrator The built entity hidrator. + * @return \Doctrine\ORM\Cache\EntityHydrator The built entity hydrator. */ public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata); /** - * Build a collection hidrator + * Build a collection hydrator * * @param \Doctrine\ORM\EntityManagerInterface $em The Entity manager. * @param array $mapping The association mapping. * - * @return \Doctrine\ORM\Cache\CollectionHydrator The built collection hidrator. + * @return \Doctrine\ORM\Cache\CollectionHydrator The built collection hydrator. */ public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping); @@ -317,6 +340,13 @@ It allows you to provide a specific implementation of the following components : * @return \Doctrine\ORM\Cache\Region The cache region. */ public function getRegion(array $cache); + + /** + * Build timestamp cache region + * + * @return \Doctrine\ORM\Cache\TimestampRegion The timestamp region. + */ + public function getTimestampRegion(); } Region Lifetime @@ -328,11 +358,14 @@ To specify a default lifetime for all regions or specify a different lifetime fo getSecondLevelCacheConfiguration(); + $regionConfig = $cacheConfig->getRegionsConfiguration(); //Cache Region lifetime - $config->setSecondLevelCacheRegionLifetime('my_entity_region', 3600); - $config->setSecondLevelCacheDefaultRegionLifetime(7200); + $regionConfig->setLifetime('my_entity_region', 3600); + $regionConfig->setDefaultLifetime(7200); Cache Log @@ -344,12 +377,14 @@ By providing a cache logger you should be able to get information about all cach .. code-block:: php setSecondLevelCacheLogger($logger); + $config->setSecondLevelCacheEnabled(true); + $config->getSecondLevelCacheConfiguration() + ->setCacheLogger($logger); // Collect cache statistics @@ -456,8 +491,8 @@ Entity cache definition ----------------------- * Entity cache configuration allows you to define the caching strategy and region for an entity. - * ``usage`` Specifies the caching strategy: ``READ_ONLY``, ``NONSTRICT_READ_WRITE``, ``READ_WRITE`` - * ``region`` Specifies the name of the second level cache region. + * ``usage`` Specifies the caching strategy: ``READ_ONLY``, ``NONSTRICT_READ_WRITE``, ``READ_WRITE``. see :ref:`reference-second-level-cache-mode` + * ``region`` Optional value that specifies the name of the second level cache region. .. configuration-block:: @@ -729,6 +764,57 @@ The query cache stores the results of the query but as identifiers, entity value ->setCacheable(true) ->getResult(); +Cache mode +~~~~~~~~~~ + +The Cache Mode controls how a particular query interacts with the second-level cache: + +* ``Cache::MODE_GET`` - May read items from the cache, but will not add items. +* ``Cache::MODE_PUT`` - Will never read items from the cache, but will add items to the cache as it reads them from the database. +* ``Cache::MODE_NORMAL`` - May read items from the cache, and add items to the cache. +* ``Cache::MODE_REFRESH`` - The query will never read items from the cache, but will refresh items to the cache as it reads them from the database. + +.. code-block:: php + + createQuery('SELECT c FROM Country c ORDER BY c.name') + ->setCacheMode(Cache::MODE_GET) + ->setCacheable(true) + ->getResult(); + +.. note:: + + The the default query cache mode is ```Cache::MODE_NORMAL``` + + +Using the repository query cache +--------------------- + +As well as ``Query Cache`` all persister queries store only identifier values for an individual query. +All persister use a single timestamps cache region keeps track of the last update for each persister, +When a query is loaded from cache, the timestamp region is checked for the last update for that persister. +Using the last update timestamps as part of the query key invalidate the cache key when an update occurs. + +.. code-block:: php + + getRepository('Entity\Country')->findAll(); + + // load from query and entities from cache.. + $entities = $em->getRepository('Country')->findAll(); + + // update the timestamp cache region for Country + $em->persist(new Country('zombieland')); + $em->flush(); + $em->clear(); + + // Reload the query from database. + $entities = $em->getRepository('Country')->findAll(); Cache API --------- @@ -785,6 +871,14 @@ Composite primary key private $target; } + // Supported + /** @var $article Article */ + $article = $this->_em->find("Article", 1); + + // Supported + /** @var $article Article */ + $article = $this->_em->find("Article", $article); + // Supported $id = array('source' => 1, 'target' => 2); $reference = $this->_em->find("Reference", $id); diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index cfc3e22dd..67606a0f9 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -22,7 +22,7 @@ namespace Doctrine\ORM; use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\Cache\QueryCacheKey; use Doctrine\DBAL\Cache\QueryCacheProfile; @@ -127,7 +127,7 @@ abstract class AbstractQuery * * @var boolean */ - protected $cacheable; + protected $cacheable = false; /** * Second level cache region name. @@ -216,7 +216,7 @@ abstract class AbstractQuery } /** - * @return boolean TRUE if the query cache and second level cache are anabled, FALSE otherwise. + * @return boolean TRUE if the query cache and second level cache are enabled, FALSE otherwise. */ protected function isCacheEnabled() { @@ -340,7 +340,7 @@ abstract class AbstractQuery $parameterCollection = new ArrayCollection(); foreach ($parameters as $key => $value) { - $parameter = new Query\Parameter($key, $value); + $parameter = new Parameter($key, $value); $parameterCollection->add($parameter); } @@ -381,7 +381,7 @@ abstract class AbstractQuery return $this; } - $parameter = new Query\Parameter($key, $value, $type); + $parameter = new Parameter($key, $value, $type); $this->parameters->add($parameter); @@ -395,10 +395,14 @@ abstract class AbstractQuery * * @return array * - * @throws ORMInvalidArgumentException + * @throws \Doctrine\ORM\ORMInvalidArgumentException */ public function processParameterValue($value) { + if (is_scalar($value)) { + return $value; + } + if (is_array($value)) { foreach ($value as $key => $paramValue) { $paramValue = $this->processParameterValue($paramValue); @@ -889,7 +893,7 @@ abstract class AbstractQuery $this->setParameters($parameters); } - $rsm = $this->_resultSetMapping ?: $this->getResultSetMapping(); + $rsm = $this->getResultSetMapping(); $stmt = $this->_doExecute(); return $this->_em->newHydrator($this->_hydrationMode)->iterate($stmt, $rsm, $this->_hints); @@ -962,7 +966,7 @@ abstract class AbstractQuery return $stmt; } - $rsm = $this->_resultSetMapping ?: $this->getResultSetMapping(); + $rsm = $this->getResultSetMapping(); $data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints); $setCacheEntry($data); @@ -980,13 +984,12 @@ abstract class AbstractQuery */ private function executeUsingQueryCache($parameters = null, $hydrationMode = null) { - $rsm = $this->_resultSetMapping ?: $this->getResultSetMapping(); + $rsm = $this->getResultSetMapping(); $querykey = new QueryCacheKey($this->getHash(), $this->lifetime, $this->cacheMode ?: Cache::MODE_NORMAL); $queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion); - $result = $queryCache->get($querykey, $rsm); + $result = $queryCache->get($querykey, $rsm, $this->_hints); if ($result !== null) { - if ($this->cacheLogger) { $this->cacheLogger->queryCacheHit($queryCache->getRegion()->getName(), $querykey); } @@ -995,14 +998,14 @@ abstract class AbstractQuery } $result = $this->executeIgnoreQueryCache($parameters, $hydrationMode); - $cached = $queryCache->put($querykey, $rsm, $result); + $cached = $queryCache->put($querykey, $rsm, $result, $this->_hints); if ($this->cacheLogger) { $this->cacheLogger->queryCacheMiss($queryCache->getRegion()->getName(), $querykey); - } - if ($this->cacheLogger && $cached) { - $this->cacheLogger->queryCachePut($queryCache->getRegion()->getName(), $querykey); + if ($cached) { + $this->cacheLogger->queryCachePut($queryCache->getRegion()->getName(), $querykey); + } } return $result; @@ -1089,15 +1092,18 @@ abstract class AbstractQuery */ protected function getHash() { - $hints = $this->getHints(); + $self = $this; $query = $this->getSQL(); - $params = array(); + $hints = $this->getHints(); + $params = array_map(function(Parameter $parameter) use ($self) { + // Small optimization + // Does not invoke processParameterValue for scalar values + if (is_scalar($value = $parameter->getValue())) { + return $value; + } - foreach ($this->parameters as $parameter) { - $value = $parameter->getValue(); - - $params[$parameter->getName()] = is_scalar($value) ? $value : $this->processParameterValue($value); - } + return $self->processParameterValue($value); + }, $this->parameters->getValues()); ksort($hints); diff --git a/lib/Doctrine/ORM/Cache.php b/lib/Doctrine/ORM/Cache.php index 068591253..6cd8b4814 100644 --- a/lib/Doctrine/ORM/Cache.php +++ b/lib/Doctrine/ORM/Cache.php @@ -51,7 +51,7 @@ interface Cache const MODE_NORMAL = 3; /** - * The session will never read items from the cache, + * The query will never read items from the cache, * but will refresh items to the cache as it reads them from the database. */ const MODE_REFRESH = 4; @@ -59,7 +59,7 @@ interface Cache /** * Construct * - * @param \Doctrine\ORMEntityManagerInterface $em + * @param \Doctrine\ORM\EntityManagerInterface $em */ public function __construct(EntityManagerInterface $em); diff --git a/lib/Doctrine/ORM/Cache/CacheConfiguration.php b/lib/Doctrine/ORM/Cache/CacheConfiguration.php index 78540f3f7..42a1ba3ba 100644 --- a/lib/Doctrine/ORM/Cache/CacheConfiguration.php +++ b/lib/Doctrine/ORM/Cache/CacheConfiguration.php @@ -98,7 +98,7 @@ class CacheConfiguration */ public function getRegionsConfiguration() { - if ($this->regionsConfig == null) { + if ($this->regionsConfig === null) { $this->regionsConfig = new RegionsConfiguration(); } @@ -118,7 +118,7 @@ class CacheConfiguration */ public function getQueryValidator() { - if ($this->queryValidator == null) { + if ($this->queryValidator === null) { $this->queryValidator = new TimestampQueryCacheValidator(); } @@ -136,7 +136,7 @@ class CacheConfiguration /** * @param string $className * - * @throws ORMException If not is a \Doctrine\ORM\Cache + * @throws \Doctrine\ORM\ORMException If is not a \Doctrine\ORM\Cache */ public function setCacheClassName($className) { diff --git a/lib/Doctrine/ORM/Cache/CacheEntry.php b/lib/Doctrine/ORM/Cache/CacheEntry.php index cdcb6c0fb..c34b0ff9b 100644 --- a/lib/Doctrine/ORM/Cache/CacheEntry.php +++ b/lib/Doctrine/ORM/Cache/CacheEntry.php @@ -23,6 +23,10 @@ namespace Doctrine\ORM\Cache; /** * Cache entry interface * + * IMPORTANT NOTE: + * + * Fields of classes that implement CacheEntry are public for performance reason. + * * @since 2.5 * @author Fabio B. Silva */ diff --git a/lib/Doctrine/ORM/Cache/CacheFactory.php b/lib/Doctrine/ORM/Cache/CacheFactory.php index 01ffa45c9..b1ce7f8e3 100644 --- a/lib/Doctrine/ORM/Cache/CacheFactory.php +++ b/lib/Doctrine/ORM/Cache/CacheFactory.php @@ -27,6 +27,8 @@ use Doctrine\ORM\Persisters\CollectionPersister; use Doctrine\ORM\Persisters\EntityPersister; /** + * Contract for building second level cache regions components. + * * @since 2.5 * @author Fabio B. Silva */ diff --git a/lib/Doctrine/ORM/Cache/CollectionHydrator.php b/lib/Doctrine/ORM/Cache/CollectionHydrator.php index 9b3141dd5..05f0d35a1 100644 --- a/lib/Doctrine/ORM/Cache/CollectionHydrator.php +++ b/lib/Doctrine/ORM/Cache/CollectionHydrator.php @@ -26,7 +26,7 @@ use Doctrine\ORM\Cache\CollectionCacheKey; use Doctrine\ORM\Cache\CollectionCacheEntry; /** - * Hidrator cache entry for collections + * Hydrator cache entry for collections * * @since 2.5 * @author Fabio B. Silva @@ -46,7 +46,7 @@ interface CollectionHydrator * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata The owning entity metadata. * @param \Doctrine\ORM\Cache\CollectionCacheKey $key The cached collection key. * @param \Doctrine\ORM\Cache\CollectionCacheEntry $entry The cached collection entry. - * @param Doctrine\ORM\PersistentCollection $collection The collection to load the cache into. + * @param \Doctrine\ORM\PersistentCollection $collection The collection to load the cache into. * * @return array */ diff --git a/lib/Doctrine/ORM/Cache/DefaultCache.php b/lib/Doctrine/ORM/Cache/DefaultCache.php index 1e76653d9..cd4c52ca0 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultCache.php @@ -22,10 +22,8 @@ namespace Doctrine\ORM\Cache; use Doctrine\ORM\Cache; use Doctrine\Common\Util\ClassUtils; -use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Cache\CollectionCacheKey; use Doctrine\ORM\Cache\Persister\CachedPersister; use Doctrine\ORM\ORMInvalidArgumentException; @@ -111,13 +109,12 @@ class DefaultCache implements Cache { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - $key = $this->buildEntityCacheKey($metadata, $identifier); if ( ! ($persister instanceof CachedPersister)) { return false; } - return $persister->getCacheRegion()->contains($key); + return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier)); } /** @@ -127,13 +124,12 @@ class DefaultCache implements Cache { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getEntityPersister($metadata->rootEntityName); - $key = $this->buildEntityCacheKey($metadata, $identifier); if ( ! ($persister instanceof CachedPersister)) { return; } - $persister->getCacheRegion()->evict($key); + $persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier)); } /** @@ -176,13 +172,12 @@ class DefaultCache implements Cache { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - $key = $this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier); if ( ! ($persister instanceof CachedPersister)) { return false; } - return $persister->getCacheRegion()->contains($key); + return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); } /** @@ -192,13 +187,12 @@ class DefaultCache implements Cache { $metadata = $this->em->getClassMetadata($className); $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); - $key = $this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier); if ( ! ($persister instanceof CachedPersister)) { return; } - $persister->getCacheRegion()->evict($key); + $persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier)); } /** diff --git a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php index 24898bb56..5781f3936 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php +++ b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php @@ -20,17 +20,17 @@ namespace Doctrine\ORM\Cache; +use Doctrine\Common\Cache\CacheProvider; + use Doctrine\ORM\Cache; use Doctrine\ORM\Cache\Region; use Doctrine\ORM\Cache\TimestampRegion; - use Doctrine\ORM\Cache\RegionsConfiguration; 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\Common\Cache\Cache as CacheDriver; use Doctrine\ORM\Persisters\EntityPersister; use Doctrine\ORM\Persisters\CollectionPersister; use Doctrine\ORM\Cache\Persister\ReadOnlyCachedEntityPersister; @@ -47,7 +47,7 @@ use Doctrine\ORM\Cache\Persister\NonStrictReadWriteCachedCollectionPersister; class DefaultCacheFactory implements CacheFactory { /** - * @var \Doctrine\Common\Cache\Cache + * @var \Doctrine\Common\Cache\CacheProvider */ private $cache; @@ -73,9 +73,9 @@ class DefaultCacheFactory implements CacheFactory /** * @param \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig - * @param \Doctrine\Common\Cache\Cache $cache + * @param \Doctrine\Common\Cache\CacheProvider $cache */ - public function __construct(RegionsConfiguration $cacheConfig, CacheDriver $cache) + public function __construct(RegionsConfiguration $cacheConfig, CacheProvider $cache) { $this->cache = $cache; $this->regionsConfig = $cacheConfig; @@ -113,7 +113,6 @@ class DefaultCacheFactory implements CacheFactory $this->timestampRegion = $region; } - /** * {@inheritdoc} */ @@ -202,7 +201,7 @@ class DefaultCacheFactory implements CacheFactory if ( ! $this->fileLockRegionDirectory) { throw new \RuntimeException( - 'To use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' . + 'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' . 'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you what to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). ' ); } diff --git a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php index c1648fb7b..479bfbfea 100644 --- a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php @@ -89,7 +89,7 @@ class DefaultQueryCache implements QueryCache /** * {@inheritdoc} */ - public function get(QueryCacheKey $key, ResultSetMapping $rsm) + public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = array()) { if ( ! ($key->cacheMode & Cache::MODE_GET)) { return null; @@ -108,13 +108,13 @@ class DefaultQueryCache implements QueryCache } $result = array(); - $entityName = reset($rsm->aliasMap); //@TODO find root entity + $entityName = reset($rsm->aliasMap); $hasRelation = ( ! empty($rsm->relationMap)); $persister = $this->uow->getEntityPersister($entityName); $region = $persister->getCacheRegion(); $regionName = $region->getName(); - // @TODO - move to cache hydration componente + // @TODO - move to cache hydration component foreach ($entry->result as $index => $entry) { if (($entityEntry = $region->get($entityKey = new EntityCacheKey($entityName, $entry['identifier']))) === null) { @@ -204,10 +204,18 @@ class DefaultQueryCache implements QueryCache /** * {@inheritdoc} */ - public function put(QueryCacheKey $key, ResultSetMapping $rsm, array $result) + public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = array()) { if ($rsm->scalarMappings) { - throw new CacheException("Second level cache does not suport scalar results."); + throw new CacheException("Second level cache does not support scalar results."); + } + + if (count($rsm->entityMappings) > 1) { + throw new CacheException("Second level cache does not support multiple root entities."); + } + + if ( ! $rsm->isSelect) { + throw new CacheException("Second-level cache query supports only select statements."); } if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD]) && $hints[Query::HINT_FORCE_PARTIAL_LOAD]) { @@ -219,7 +227,7 @@ class DefaultQueryCache implements QueryCache } $data = array(); - $entityName = reset($rsm->aliasMap); //@TODO find root entity + $entityName = reset($rsm->aliasMap); $hasRelation = ( ! empty($rsm->relationMap)); $metadata = $this->em->getClassMetadata($entityName); $persister = $this->uow->getEntityPersister($entityName); @@ -246,7 +254,7 @@ class DefaultQueryCache implements QueryCache continue; } - // @TODO - move to cache hydration componente + // @TODO - move to cache hydration components foreach ($rsm->relationMap as $name) { $assoc = $metadata->associationMappings[$name]; diff --git a/lib/Doctrine/ORM/Cache/EntityHydrator.php b/lib/Doctrine/ORM/Cache/EntityHydrator.php index 3e382cd75..569561101 100644 --- a/lib/Doctrine/ORM/Cache/EntityHydrator.php +++ b/lib/Doctrine/ORM/Cache/EntityHydrator.php @@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Cache\EntityCacheEntry; /** - * Hidrator cache entry for entities + * Hydrator cache entry for entities * * @since 2.5 * @author Fabio B. Silva diff --git a/lib/Doctrine/ORM/Cache/Persister/AbstractCollectionPersister.php b/lib/Doctrine/ORM/Cache/Persister/AbstractCollectionPersister.php index ca56a1bcc..baacbd4c2 100644 --- a/lib/Doctrine/ORM/Cache/Persister/AbstractCollectionPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/AbstractCollectionPersister.php @@ -145,7 +145,6 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister */ public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key) { - if (($cache = $this->region->get($key)) === null) { return null; } @@ -164,7 +163,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister { $targetPersister = $this->uow->getEntityPersister($this->targetEntity->rootEntityName); $targetRegion = $targetPersister->getCacheRegion(); - $targetHidrator = $targetPersister->getEntityHydrator(); + $targetHydrator = $targetPersister->getEntityHydrator(); $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); foreach ($entry->identifiers as $index => $identifier) { @@ -182,7 +181,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister } $entity = $elements[$index]; - $entityEntry = $targetHidrator->buildCacheEntry($class, $entityKey, $entity); + $entityEntry = $targetHydrator->buildCacheEntry($class, $entityKey, $entity); $targetRegion->put($entityKey, $entityEntry); } diff --git a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php index 4eeef07e7..4f78c7354 100644 --- a/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/AbstractEntityPersister.php @@ -179,7 +179,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister public function exists($entity, array $extraConditions = array()) { if (empty($extraConditions)) { - $key = new EntityCacheKey($this->class->rootEntityName, $this->class->getIdentifierValues($entity)); if ($this->region->contains($key)) { @@ -302,7 +301,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister */ public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0, $limit = null, array $orderBy = null) { - //@TODO - Should throw exception ? if ($entity !== null || $assoc !== null || ! empty($hints) || $lockMode !== 0) { return $this->persister->load($criteria, $entity, $assoc, $hints, $lockMode, $limit, $orderBy); } @@ -317,7 +315,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $result = $queryCache->get($querykey, $rsm); if ($result !== null) { - if ($this->cacheLogger) { $this->cacheLogger->queryCacheHit($this->regionName, $querykey); } @@ -331,12 +328,14 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $cached = $queryCache->put($querykey, $rsm, array($result)); - if ($this->cacheLogger && $result) { - $this->cacheLogger->queryCacheMiss($this->regionName, $querykey); - } + if ($this->cacheLogger) { + if ($result) { + $this->cacheLogger->queryCacheMiss($this->regionName, $querykey); + } - if ($this->cacheLogger && $cached) { - $this->cacheLogger->queryCachePut($this->regionName, $querykey); + if ($cached) { + $this->cacheLogger->queryCachePut($this->regionName, $querykey); + } } return $result; @@ -356,7 +355,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $result = $queryCache->get($querykey, $rsm); if ($result !== null) { - if ($this->cacheLogger) { $this->cacheLogger->queryCacheHit($this->regionName, $querykey); } @@ -367,12 +365,14 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $result = $this->persister->loadAll($criteria, $orderBy, $limit, $offset); $cached = $queryCache->put($querykey, $rsm, $result); - if ($this->cacheLogger && $result) { - $this->cacheLogger->queryCacheMiss($this->regionName, $querykey); - } + if ($this->cacheLogger) { + if ($result) { + $this->cacheLogger->queryCacheMiss($this->regionName, $querykey); + } - if ($this->cacheLogger && $cached) { - $this->cacheLogger->queryCachePut($this->regionName, $querykey); + if ($cached) { + $this->cacheLogger->queryCachePut($this->regionName, $querykey); + } } return $result; @@ -388,13 +388,11 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $class = $this->class; if ($cacheEntry !== null) { - if ($cacheEntry->class !== $this->class->name) { $class = $this->metadataFactory->getMetadataFor($cacheEntry->class); } if (($entity = $this->hydrator->loadCacheEntry($class, $cacheKey, $cacheEntry, $entity)) !== null) { - if ($this->cacheLogger) { $this->cacheLogger->entityCacheHit($this->regionName, $cacheKey); } @@ -419,11 +417,11 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $cacheEntry = $this->hydrator->buildCacheEntry($class, $cacheKey, $entity); $cached = $this->region->put($cacheKey, $cacheEntry); - if ($this->cacheLogger && $cached) { - $this->cacheLogger->entityCachePut($this->regionName, $cacheKey); - } - if ($this->cacheLogger) { + if ($cached) { + $this->cacheLogger->entityCachePut($this->regionName, $cacheKey); + } + $this->cacheLogger->entityCacheMiss($this->regionName, $cacheKey); } @@ -453,7 +451,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $list = $persister->loadCollectionCache($coll, $key); if ($list !== null) { - if ($this->cacheLogger) { $this->cacheLogger->collectionCacheHit($persister->getCacheRegion()->getName(), $key); } @@ -489,7 +486,6 @@ abstract class AbstractEntityPersister implements CachedEntityPersister $list = $persister->loadCollectionCache($coll, $key); if ($list !== null) { - if ($this->cacheLogger) { $this->cacheLogger->collectionCacheHit($persister->getCacheRegion()->getName(), $key); } diff --git a/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedCollectionPersister.php b/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedCollectionPersister.php index 619a520b3..6f7d75596 100644 --- a/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedCollectionPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedCollectionPersister.php @@ -87,7 +87,6 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers // Invalidate non initialized collections OR odered collection if ($isDirty && ! $isInitialized || isset($this->association['orderBy'])) { - $this->persister->update($collection); $this->queuedCache['delete'][spl_object_hash($collection)] = $key; diff --git a/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedEntityPersister.php index a9a9a37e9..3d6004e96 100644 --- a/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/NonStrictReadWriteCachedEntityPersister.php @@ -41,7 +41,6 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister if (isset($this->queuedCache['insert'])) { foreach ($this->queuedCache['insert'] as $entity) { - $class = $this->class; $className = ClassUtils::getClass($entity); @@ -62,7 +61,6 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister if (isset($this->queuedCache['update'])) { foreach ($this->queuedCache['update'] as $entity) { - $class = $this->class; $className = ClassUtils::getClass($entity); diff --git a/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedCollectionPersister.php b/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedCollectionPersister.php index 573257bdd..967ccf69a 100644 --- a/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedCollectionPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedCollectionPersister.php @@ -33,11 +33,6 @@ use Doctrine\ORM\PersistentCollection; */ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister { - /** - * @var \Doctrine\ORM\Cache\ConcurrentRegion - */ - protected $region; - /** * @param \Doctrine\ORM\Persisters\CollectionPersister $persister The collection persister that will be cached. * @param \Doctrine\ORM\Cache\ConcurrentRegion $region The collection region. diff --git a/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedEntityPersister.php index d77aabf9e..1b3af3ab7 100644 --- a/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/ReadWriteCachedEntityPersister.php @@ -35,11 +35,6 @@ use Doctrine\ORM\Cache\EntityCacheKey; */ class ReadWriteCachedEntityPersister extends AbstractEntityPersister { - /** - * @var \Doctrine\ORM\Cache\ConcurrentRegion - */ - protected $region; - /** * @param \Doctrine\ORM\Persister\EntityPersister $persister The entity persister to cache. * @param \Doctrine\ORM\Cache\ConcurrentRegion $region The entity cache region. diff --git a/lib/Doctrine/ORM/Cache/QueryCache.php b/lib/Doctrine/ORM/Cache/QueryCache.php index 7bdc0d337..5eb202281 100644 --- a/lib/Doctrine/ORM/Cache/QueryCache.php +++ b/lib/Doctrine/ORM/Cache/QueryCache.php @@ -39,19 +39,21 @@ interface QueryCache /** * @param \Doctrine\ORM\Cache\QueryCacheKey $key * @param \Doctrine\ORM\Query\ResultSetMapping $rsm - * @param array $result + * @param mixed $result + * @param array $hints * * @return boolean */ - public function put(QueryCacheKey $key, ResultSetMapping $rsm, array $result); + public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = array()); /** - * @param \Doctrine\ORM\Cache\QueryCacheKey $key - * @param \Doctrine\ORM\Query\ResultSetMapping $rsm + * @param \Doctrine\ORM\Cache\QueryCacheKey $key + * @param \Doctrine\ORM\Query\ResultSetMapping $rsm + * @param array $hints * * @return void */ - public function get(QueryCacheKey $key, ResultSetMapping $rsm); + public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = array()); /** * @return \Doctrine\ORM\Cache\Region diff --git a/lib/Doctrine/ORM/Cache/QueryCacheKey.php b/lib/Doctrine/ORM/Cache/QueryCacheKey.php index 31a3d15d8..7001cc332 100644 --- a/lib/Doctrine/ORM/Cache/QueryCacheKey.php +++ b/lib/Doctrine/ORM/Cache/QueryCacheKey.php @@ -20,6 +20,8 @@ namespace Doctrine\ORM\Cache; +use Doctrine\ORM\Cache; + /** * A key that identifies a particular query. * @@ -43,7 +45,7 @@ class QueryCacheKey extends CacheKey * @param integer $lifetime Query lifetime * @param integer $cacheMode Query cache mode */ - public function __construct($hash, $lifetime = 0, $cacheMode = 3) + public function __construct($hash, $lifetime = 0, $cacheMode = Cache::MODE_NORMAL) { $this->hash = $hash; $this->lifetime = $lifetime; diff --git a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php index b5735e9f6..b4b5b1b1d 100644 --- a/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php +++ b/lib/Doctrine/ORM/Cache/Region/DefaultRegion.php @@ -34,8 +34,6 @@ use Doctrine\Common\Cache\CacheProvider; */ class DefaultRegion implements Region { - const ENTRY_KEY = '_entry_'; - /** * @var \Doctrine\Common\Cache\CacheProvider */ @@ -86,7 +84,7 @@ class DefaultRegion implements Region */ public function contains(CacheKey $key) { - return $this->cache->contains($this->name . self::ENTRY_KEY . $key->hash); + return $this->cache->contains($this->name . '_' . $key->hash); } /** @@ -94,7 +92,7 @@ class DefaultRegion implements Region */ public function get(CacheKey $key) { - return $this->cache->fetch($this->name . self::ENTRY_KEY . $key->hash) ?: null; + return $this->cache->fetch($this->name . '_' . $key->hash) ?: null; } /** @@ -102,7 +100,7 @@ class DefaultRegion implements Region */ public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null) { - return $this->cache->save($this->name . self::ENTRY_KEY . $key->hash, $entry, $this->lifetime); + return $this->cache->save($this->name . '_' . $key->hash, $entry, $this->lifetime); } /** @@ -110,7 +108,7 @@ class DefaultRegion implements Region */ public function evict(CacheKey $key) { - return $this->cache->delete($this->name . self::ENTRY_KEY . $key->hash); + return $this->cache->delete($this->name . '_' . $key->hash); } /** diff --git a/lib/Doctrine/ORM/Cache/Region/FileLockRegion.php b/lib/Doctrine/ORM/Cache/Region/FileLockRegion.php index 680f1940b..956e7634f 100644 --- a/lib/Doctrine/ORM/Cache/Region/FileLockRegion.php +++ b/lib/Doctrine/ORM/Cache/Region/FileLockRegion.php @@ -77,9 +77,9 @@ class FileLockRegion implements ConcurrentRegion * param \Doctrine\ORM\Cache\CacheKey $key * param \Doctrine\ORM\Cache\Lock $lock * - * return boolean + * @return boolean */ - private function isLoked(CacheKey $key, Lock $lock = null) + private function isLocked(CacheKey $key, Lock $lock = null) { $filename = $this->getLockFileName($key); @@ -153,7 +153,7 @@ class FileLockRegion implements ConcurrentRegion */ public function contains(CacheKey $key) { - if ($this->isLoked($key)) { + if ($this->isLocked($key)) { return false; } @@ -165,7 +165,7 @@ class FileLockRegion implements ConcurrentRegion */ public function get(CacheKey $key) { - if ($this->isLoked($key)) { + if ($this->isLocked($key)) { return null; } @@ -177,7 +177,7 @@ class FileLockRegion implements ConcurrentRegion */ public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null) { - if ($this->isLoked($key, $lock)) { + if ($this->isLocked($key, $lock)) { return false; } @@ -189,7 +189,7 @@ class FileLockRegion implements ConcurrentRegion */ public function evict(CacheKey $key) { - if ($this->isLoked($key)) { + if ($this->isLocked($key)) { @unlink($this->getLockFileName($key)); } @@ -213,7 +213,7 @@ class FileLockRegion implements ConcurrentRegion */ public function lock(CacheKey $key) { - if ($this->isLoked($key)) { + if ($this->isLocked($key)) { return null; } @@ -232,7 +232,7 @@ class FileLockRegion implements ConcurrentRegion */ public function unlock(CacheKey $key, Lock $lock) { - if ($this->isLoked($key, $lock)) { + if ($this->isLocked($key, $lock)) { return false; } diff --git a/lib/Doctrine/ORM/Cache/RegionsConfiguration.php b/lib/Doctrine/ORM/Cache/RegionsConfiguration.php index 58bcbdef9..1a847943b 100644 --- a/lib/Doctrine/ORM/Cache/RegionsConfiguration.php +++ b/lib/Doctrine/ORM/Cache/RegionsConfiguration.php @@ -97,11 +97,9 @@ class RegionsConfiguration */ public function getLifetime($regionName) { - if (isset($this->lifetimes[$regionName])) { - return $this->lifetimes[$regionName]; - } - - return $this->defaultLifetime; + return isset($this->lifetimes[$regionName]) + ? $this->lifetimes[$regionName] + : $this->defaultLifetime; } /** @@ -120,11 +118,9 @@ class RegionsConfiguration */ public function getLockLifetime($regionName) { - if (isset($this->lockLifetimes[$regionName])) { - return $this->lockLifetimes[$regionName]; - } - - return $this->defaultLockLifetime; + return isset($this->lockLifetimes[$regionName]) + ? $this->lockLifetimes[$regionName] + : $this->defaultLockLifetime; } /** diff --git a/lib/Doctrine/ORM/Cache/TimestampCacheEntry.php b/lib/Doctrine/ORM/Cache/TimestampCacheEntry.php index 3ad05c96a..f7617b3bb 100644 --- a/lib/Doctrine/ORM/Cache/TimestampCacheEntry.php +++ b/lib/Doctrine/ORM/Cache/TimestampCacheEntry.php @@ -29,12 +29,12 @@ namespace Doctrine\ORM\Cache; class TimestampCacheEntry implements CacheEntry { /** - * @var integer + * @var float */ public $time; /** - * @param array $result + * @param float $time */ public function __construct($time = null) { diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 778f44d84..c261723f7 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -82,8 +82,8 @@ class XmlDriver extends FileDriver $metadata->setPrimaryTable($table); // Evaluate second level cache - if (isset($xmlRoot->{'cache'})) { - $metadata->enableCache($this->cacheToArray($xmlRoot->{'cache'})); + if (isset($xmlRoot->cache)) { + $metadata->enableCache($this->cacheToArray($xmlRoot->cache)); } // Evaluate named queries @@ -356,8 +356,8 @@ class XmlDriver extends FileDriver $metadata->mapOneToOne($mapping); // Evaluate second level cache - if (isset($oneToOneElement->{'cache'})) { - $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToOneElement->{'cache'})); + if (isset($oneToOneElement->cache)) { + $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToOneElement->cache)); } } } @@ -400,8 +400,8 @@ class XmlDriver extends FileDriver $metadata->mapOneToMany($mapping); // Evaluate second level cache - if (isset($oneToManyElement->{'cache'})) { - $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToManyElement->{'cache'})); + if (isset($oneToManyElement->cache)) { + $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($oneToManyElement->cache)); } } } @@ -445,8 +445,8 @@ class XmlDriver extends FileDriver $metadata->mapManyToOne($mapping); // Evaluate second level cache - if (isset($manyToOneElement->{'cache'})) { - $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToOneElement->{'cache'})); + if (isset($manyToOneElement->cache)) { + $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToOneElement->cache)); } } } @@ -515,8 +515,8 @@ class XmlDriver extends FileDriver $metadata->mapManyToMany($mapping); // Evaluate second level cache - if (isset($manyToManyElement->{'cache'})) { - $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToManyElement->{'cache'})); + if (isset($manyToManyElement->cache)) { + $metadata->enableAssociationCache($mapping['fieldName'], $this->cacheToArray($manyToManyElement->cache)); } } } @@ -733,8 +733,16 @@ class XmlDriver extends FileDriver */ private function cacheToArray(SimpleXMLElement $cacheMapping) { - $region = isset($cacheMapping['region']) ? (string)$cacheMapping['region'] : null; - $usage = isset($cacheMapping['usage']) ? constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . strtoupper($cacheMapping['usage'])) : null; + $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null; + $usage = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null; + + if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) { + throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage)); + } + + if ($usage) { + $usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage); + } return array( 'usage' => $usage, diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 80b2d6a2a..e5eac7e4f 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -738,8 +738,16 @@ class YamlDriver extends FileDriver */ private function cacheToArray($cacheMapping) { - $region = isset($cacheMapping['region']) ? (string)$cacheMapping['region'] : null; - $usage = isset($cacheMapping['usage']) ? constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . strtoupper($cacheMapping['usage'])) : null; + $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null; + $usage = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null; + + if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) { + throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage)); + } + + if ($usage) { + $usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage); + } return array( 'usage' => $usage, diff --git a/lib/Doctrine/ORM/ORMException.php b/lib/Doctrine/ORM/ORMException.php index 8349c4f6d..b9a0b9cec 100644 --- a/lib/Doctrine/ORM/ORMException.php +++ b/lib/Doctrine/ORM/ORMException.php @@ -109,7 +109,7 @@ class ORMException extends Exception * * @return \Doctrine\ORM\ORMInvalidArgumentException */ - static public function unexpectedAssociationValue($class, $association, $given, $expected) + public static function unexpectedAssociationValue($class, $association, $given, $expected) { return new self(sprintf('Found entity of type %s on association %s#%s, but expecting %s', $given, $class, $association, $expected)); } diff --git a/lib/Doctrine/ORM/Persisters/CollectionPersister.php b/lib/Doctrine/ORM/Persisters/CollectionPersister.php index f8d194442..f99d57805 100644 --- a/lib/Doctrine/ORM/Persisters/CollectionPersister.php +++ b/lib/Doctrine/ORM/Persisters/CollectionPersister.php @@ -73,8 +73,6 @@ interface CollectionPersister * @param \Doctrine\ORM\PersistentCollection $collection * * @return integer - * - * @throws \BadMethodCallException */ public function count(PersistentCollection $collection); diff --git a/lib/Doctrine/ORM/Persisters/EntityPersister.php b/lib/Doctrine/ORM/Persisters/EntityPersister.php index a27a59d14..fde9d5540 100644 --- a/lib/Doctrine/ORM/Persisters/EntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/EntityPersister.php @@ -22,7 +22,6 @@ namespace Doctrine\ORM\Persisters; use Doctrine\ORM\PersistentCollection; use Doctrine\Common\Collections\Criteria; - /** * Entity persister interface * Define the behavior that should be implemented by all entity persisters. diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index de8411df0..1722d58a3 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -309,7 +309,7 @@ final class Query extends AbstractQuery foreach ($this->parameters as $parameter) { $key = $parameter->getName(); $value = $parameter->getValue(); - $rsm = $this->_resultSetMapping ?: $this->getResultSetMapping(); + $rsm = $this->getResultSetMapping(); if ( ! isset($paramMappings[$key])) { throw QueryException::unknownParameter($key); diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php index f4d11cf44..07b896695 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMapping.php +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -43,6 +43,14 @@ class ResultSetMapping */ public $isMixed = false; + /** + * Whether the result is a select statement. + * + * @ignore + * @var boolean + */ + public $isSelect = true; + /** * Maps alias names to class names. * diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 0852664ec..cdb1bb24f 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -573,6 +573,7 @@ class SqlWalker implements TreeWalker public function walkUpdateStatement(AST\UpdateStatement $AST) { $this->useSqlTableAliases = false; + $this->rsm->isSelect = false; return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause); @@ -584,6 +585,7 @@ class SqlWalker implements TreeWalker public function walkDeleteStatement(AST\DeleteStatement $AST) { $this->useSqlTableAliases = false; + $this->rsm->isSelect = false; return $this->walkDeleteClause($AST->deleteClause) . $this->walkWhereClause($AST->whereClause); diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index e0909d4b6..023f742ab 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -2539,7 +2539,7 @@ class UnitOfWork implements PropertyChangedListener $overrideLocalValues = isset($hints[Query::HINT_REFRESH]); // If only a specific entity is set to refresh, check that it's the one - if(isset($hints[Query::HINT_REFRESH_ENTITY])) { + if (isset($hints[Query::HINT_REFRESH_ENTITY])) { $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity; } @@ -3255,13 +3255,13 @@ class UnitOfWork implements PropertyChangedListener } foreach ($this->persisters as $persister) { - if($persister instanceof CachedPersister) { + if ($persister instanceof CachedPersister) { $persister->afterTransactionComplete(); } } foreach ($this->collectionPersisters as $persister) { - if($persister instanceof CachedPersister) { + if ($persister instanceof CachedPersister) { $persister->afterTransactionComplete(); } } @@ -3277,13 +3277,13 @@ class UnitOfWork implements PropertyChangedListener } foreach ($this->persisters as $persister) { - if($persister instanceof CachedPersister) { + if ($persister instanceof CachedPersister) { $persister->afterTransactionRolledBack(); } } foreach ($this->collectionPersisters as $persister) { - if($persister instanceof CachedPersister) { + if ($persister instanceof CachedPersister) { $persister->afterTransactionRolledBack(); } } diff --git a/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php b/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php index 9f5f4cc39..243f9b63e 100644 --- a/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php +++ b/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php @@ -17,7 +17,7 @@ class CacheMetadataListener 'usage' => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE ); - /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */ + /** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */ if (strstr($metadata->name, 'Doctrine\Tests\Models\Cache')) { return; } diff --git a/tests/Doctrine/Tests/Mocks/CacheRegionMock.php b/tests/Doctrine/Tests/Mocks/CacheRegionMock.php index 06a40c2eb..a4ef52ca3 100644 --- a/tests/Doctrine/Tests/Mocks/CacheRegionMock.php +++ b/tests/Doctrine/Tests/Mocks/CacheRegionMock.php @@ -18,13 +18,13 @@ class CacheRegionMock implements Region $this->returns[$method][] = $value; } - public function getReturn($method, $datault) + public function getReturn($method, $default) { if (isset($this->returns[$method]) && ! empty($this->returns[$method])) { return array_shift($this->returns[$method]); } - return $datault; + return $default; } public function getName() diff --git a/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php b/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php index a84672bea..e299f2a70 100644 --- a/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php +++ b/tests/Doctrine/Tests/Mocks/ConcurrentRegionMock.php @@ -31,7 +31,7 @@ class ConcurrentRegionMock implements ConcurrentRegion if (isset($this->exceptions[$method]) && ! empty($this->exceptions[$method])) { $exception = array_shift($this->exceptions[$method]); - if($exception != null) { + if ($exception != null) { throw $exception; } } diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php index fa7cb219a..f597a5134 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php @@ -253,7 +253,7 @@ class DefaultCacheFactoryTest extends OrmTestCase /** * @expectedException RuntimeException - * @expectedExceptionMessage To use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you what to use it please provide a valid directory + * @expectedExceptionMessage If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you what to use it please provide a valid directory */ public function testInvalidFileLockRegionDirectoryException() { diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php index fed80adc0..dfe385813 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php @@ -236,7 +236,7 @@ class DefaultQueryCacheTest extends OrmTestCase $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); - $result = $this->queryCache->get($key, $rsm, $entry); + $result = $this->queryCache->get($key, $rsm); $this->assertCount(2, $result); $this->assertInstanceOf(Country::CLASSNAME, $result[0]); @@ -349,7 +349,7 @@ class DefaultQueryCacheTest extends OrmTestCase $this->region->addReturn('get', $entry); - $this->assertNull($this->queryCache->get($key, $rsm, $entry)); + $this->assertNull($this->queryCache->get($key, $rsm)); } public function testIgnoreCacheNonPutMode() @@ -394,7 +394,7 @@ class DefaultQueryCacheTest extends OrmTestCase $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); - $this->assertNull($this->queryCache->get($key, $rsm, $entry)); + $this->assertNull($this->queryCache->get($key, $rsm)); } public function testGetShouldIgnoreNonQueryCacheEntryResult() @@ -417,7 +417,7 @@ class DefaultQueryCacheTest extends OrmTestCase $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); - $this->assertNull($this->queryCache->get($key, $rsm, $entry)); + $this->assertNull($this->queryCache->get($key, $rsm)); } public function testGetShouldIgnoreMissingEntityQueryCacheEntry() @@ -434,7 +434,7 @@ class DefaultQueryCacheTest extends OrmTestCase $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); - $this->assertNull($this->queryCache->get($key, $rsm, $entry)); + $this->assertNull($this->queryCache->get($key, $rsm)); } /** @@ -463,7 +463,7 @@ class DefaultQueryCacheTest extends OrmTestCase /** * @expectedException Doctrine\ORM\Cache\CacheException - * @expectedExceptionMessage Second level cache does not suport scalar results. + * @expectedExceptionMessage Second level cache does not support scalar results. */ public function testScalarResultException() { @@ -476,6 +476,22 @@ class DefaultQueryCacheTest extends OrmTestCase $this->queryCache->put($key, $rsm, $result); } + /** + * @expectedException Doctrine\ORM\Cache\CacheException + * @expectedExceptionMessage Second level cache does not support multiple root entities. + */ + public function testSuportMultipleRootEntitiesException() + { + $result = array(); + $key = new QueryCacheKey('query.key1', 0); + $rsm = new ResultSetMappingBuilder($this->em); + + $rsm->addEntityResult('Doctrine\Tests\Models\Cache\City', 'e1'); + $rsm->addEntityResult('Doctrine\Tests\Models\Cache\State', 'e2'); + + $this->queryCache->put($key, $rsm, $result); + } + /** * @expectedException Doctrine\ORM\Cache\CacheException * @expectedExceptionMessage Entity "Doctrine\Tests\Models\Generic\BooleanModel" not configured as part of the second-level cache. diff --git a/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php b/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php index 94cd3985d..e699bb39f 100644 --- a/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/FileLockRegionTest.php @@ -8,7 +8,6 @@ use Doctrine\ORM\Cache\ConcurrentRegion; use Doctrine\Tests\Mocks\CacheEntryMock; use Doctrine\Tests\Mocks\CacheKeyMock; use Doctrine\ORM\Cache\CacheKey; -use Doctrine\ORM\Cache\Lock; use RecursiveIteratorIterator; use RecursiveDirectoryIterator; diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php index fa8e20b53..593073e8d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php @@ -18,8 +18,6 @@ use Doctrine\Tests\Models\Cache\Bar; use Doctrine\Tests\Models\Cache\AttractionContactInfo; use Doctrine\Tests\Models\Cache\AttractionLocationInfo; -require_once __DIR__ . '/../../TestInit.php'; - /** * @group DDC-2183 */ diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositPrimaryKeyTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositePrimaryKeyTest.php similarity index 98% rename from tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositPrimaryKeyTest.php rename to tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositePrimaryKeyTest.php index 5c58b0aaa..f5c105225 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositPrimaryKeyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheCompositePrimaryKeyTest.php @@ -2,14 +2,13 @@ namespace Doctrine\Tests\ORM\Functional; - use Doctrine\Tests\Models\Cache\City; use Doctrine\Tests\Models\Cache\Flight; /** * @group DDC-2183 */ -class SecondLevelCacheCompositPrimaryKeyTest extends SecondLevelCacheAbstractTest +class SecondLevelCacheCompositePrimaryKeyTest extends SecondLevelCacheAbstractTest { public function testPutAndLoadCompositPrimaryKeyEntities() { diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheExtraLazyCollectionTest.php index b96c41e1f..366f846f8 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheExtraLazyCollectionTest.php @@ -2,7 +2,6 @@ namespace Doctrine\Tests\ORM\Functional; - use Doctrine\Tests\Models\Cache\City; use Doctrine\Tests\Models\Cache\State; use Doctrine\Tests\Models\Cache\Travel; diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php index b063cd319..e81b08b96 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheJoinTableInheritanceTest.php @@ -7,7 +7,6 @@ use Doctrine\Tests\Models\Cache\AttractionInfo; use Doctrine\Tests\Models\Cache\AttractionContactInfo; use Doctrine\Tests\Models\Cache\AttractionLocationInfo; - /** * @group DDC-2183 */ diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php index 931ba88ba..c00820c91 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheOneToManyTest.php @@ -2,7 +2,6 @@ namespace Doctrine\Tests\ORM\Functional; - use Doctrine\Tests\Models\Cache\City; use Doctrine\Tests\Models\Cache\State; use Doctrine\Tests\Models\Cache\Travel; diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php index c326128cb..70dbf3cd3 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php @@ -9,6 +9,7 @@ use Doctrine\Tests\Models\Cache\City; use Doctrine\ORM\Cache\QueryCacheKey; use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\Cache\EntityCacheEntry; +use Doctrine\ORM\Query; use Doctrine\ORM\Cache; /** @@ -840,4 +841,26 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheAbstractTest ->setCacheable(true) ->getResult(); } + + /** + * @expectedException \Doctrine\ORM\Cache\CacheException + * @expectedExceptionMessage Second-level cache query supports only select statements. + */ + public function testNonCacheableQueryDeleteStatementException() + { + $this->_em->createQuery('DELETE Doctrine\Tests\Models\Cache\Country u WHERE u.id = 4') + ->setCacheable(true) + ->getResult(); + } + + /** + * @expectedException \Doctrine\ORM\Cache\CacheException + * @expectedExceptionMessage Second-level cache query supports only select statements. + */ + public function testNonCacheableQueryUpdateStatementException() + { + $this->_em->createQuery('UPDATE Doctrine\Tests\Models\Cache\Country u SET u.name = NULL WHERE u.id = 4') + ->setCacheable(true) + ->getResult(); + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Performance/SecondLevelCacheTest.php b/tests/Doctrine/Tests/ORM/Performance/SecondLevelCacheTest.php index 3e628acbd..61b9c7ce7 100644 --- a/tests/Doctrine/Tests/ORM/Performance/SecondLevelCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Performance/SecondLevelCacheTest.php @@ -9,8 +9,6 @@ use Doctrine\Tests\Models\Cache\State; use Doctrine\Tests\Models\Cache\City; use Doctrine\ORM\EntityManagerInterface; -require_once __DIR__ . '/../../TestInit.php'; - /** * @group DDC-2183 * @group performance diff --git a/tests/Doctrine/Tests/OrmTestCase.php b/tests/Doctrine/Tests/OrmTestCase.php index 8546fae03..fc713805a 100644 --- a/tests/Doctrine/Tests/OrmTestCase.php +++ b/tests/Doctrine/Tests/OrmTestCase.php @@ -10,7 +10,6 @@ use Doctrine\ORM\Cache\DefaultCacheFactory; */ abstract class OrmTestCase extends DoctrineTestCase { - /** * The metadata cache that is shared between all ORM tests (except functional tests). *