vendor/doctrine/orm/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php line 364

Open in your IDE?
  1. <?php
  2. /*
  3.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14.  *
  15.  * This software consists of voluntary contributions made by many individuals
  16.  * and is licensed under the MIT license. For more information, see
  17.  * <http://www.doctrine-project.org>.
  18.  */
  19. namespace Doctrine\ORM\Cache\Persister\Entity;
  20. use Doctrine\ORM\Cache;
  21. use Doctrine\ORM\Cache\Region;
  22. use Doctrine\ORM\Cache\EntityCacheKey;
  23. use Doctrine\ORM\Cache\CollectionCacheKey;
  24. use Doctrine\ORM\Cache\TimestampCacheKey;
  25. use Doctrine\ORM\Cache\QueryCacheKey;
  26. use Doctrine\ORM\Cache\Persister\CachedPersister;
  27. use Doctrine\ORM\Mapping\ClassMetadata;
  28. use Doctrine\ORM\PersistentCollection;
  29. use Doctrine\ORM\EntityManagerInterface;
  30. use Doctrine\ORM\Persisters\Entity\EntityPersister;
  31. use Doctrine\Common\Util\ClassUtils;
  32. use Doctrine\Common\Collections\Criteria;
  33. /**
  34.  * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
  35.  * @since 2.5
  36.  */
  37. abstract class AbstractEntityPersister implements CachedEntityPersister
  38. {
  39.      /**
  40.      * @var \Doctrine\ORM\UnitOfWork
  41.      */
  42.     protected $uow;
  43.     /**
  44.      * @var \Doctrine\ORM\Mapping\ClassMetadataFactory
  45.      */
  46.     protected $metadataFactory;
  47.     /**
  48.      * @var \Doctrine\ORM\Persisters\Entity\EntityPersister
  49.      */
  50.     protected $persister;
  51.     /**
  52.      * @var \Doctrine\ORM\Mapping\ClassMetadata
  53.      */
  54.     protected $class;
  55.      /**
  56.      * @var array
  57.      */
  58.     protected $queuedCache = [];
  59.     /**
  60.      * @var \Doctrine\ORM\Cache\Region
  61.      */
  62.     protected $region;
  63.     /**
  64.      * @var \Doctrine\ORM\Cache\TimestampRegion
  65.      */
  66.     protected $timestampRegion;
  67.     /**
  68.      * @var \Doctrine\ORM\Cache\TimestampCacheKey
  69.      */
  70.     protected $timestampKey;
  71.     /**
  72.      * @var \Doctrine\ORM\Cache\EntityHydrator
  73.      */
  74.     protected $hydrator;
  75.     /**
  76.      * @var \Doctrine\ORM\Cache
  77.      */
  78.     protected $cache;
  79.     /**
  80.      * @var \Doctrine\ORM\Cache\Logging\CacheLogger
  81.      */
  82.     protected $cacheLogger;
  83.     /**
  84.      * @var string
  85.      */
  86.     protected $regionName;
  87.     /**
  88.      * Associations configured as FETCH_EAGER, as well as all inverse one-to-one associations.
  89.      *
  90.      * @var array|null
  91.      */
  92.     protected $joinedAssociations;
  93.     /**
  94.      * @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister The entity persister to cache.
  95.      * @param \Doctrine\ORM\Cache\Region                      $region    The entity cache region.
  96.      * @param \Doctrine\ORM\EntityManagerInterface            $em        The entity manager.
  97.      * @param \Doctrine\ORM\Mapping\ClassMetadata             $class     The entity metadata.
  98.      */
  99.     public function __construct(EntityPersister $persisterRegion $regionEntityManagerInterface $emClassMetadata $class)
  100.     {
  101.         $configuration  $em->getConfiguration();
  102.         $cacheConfig    $configuration->getSecondLevelCacheConfiguration();
  103.         $cacheFactory   $cacheConfig->getCacheFactory();
  104.         $this->class            $class;
  105.         $this->region           $region;
  106.         $this->persister        $persister;
  107.         $this->cache            $em->getCache();
  108.         $this->regionName       $region->getName();
  109.         $this->uow              $em->getUnitOfWork();
  110.         $this->metadataFactory  $em->getMetadataFactory();
  111.         $this->cacheLogger      $cacheConfig->getCacheLogger();
  112.         $this->timestampRegion  $cacheFactory->getTimestampRegion();
  113.         $this->hydrator         $cacheFactory->buildEntityHydrator($em$class);
  114.         $this->timestampKey     = new TimestampCacheKey($this->class->rootEntityName);
  115.     }
  116.     /**
  117.      * {@inheritdoc}
  118.      */
  119.     public function addInsert($entity)
  120.     {
  121.         $this->persister->addInsert($entity);
  122.     }
  123.     /**
  124.      * {@inheritdoc}
  125.      */
  126.     public function getInserts()
  127.     {
  128.         return $this->persister->getInserts();
  129.     }
  130.     /**
  131.      * {@inheritdoc}
  132.      */
  133.     public function getSelectSQL($criteria$assoc null$lockMode null$limit null$offset null, array $orderBy null)
  134.     {
  135.         return $this->persister->getSelectSQL($criteria$assoc$lockMode$limit$offset$orderBy);
  136.     }
  137.     /**
  138.      * {@inheritDoc}
  139.      */
  140.     public function getCountSQL($criteria = [])
  141.     {
  142.         return $this->persister->getCountSQL($criteria);
  143.     }
  144.     /**
  145.      * {@inheritdoc}
  146.      */
  147.     public function getInsertSQL()
  148.     {
  149.         return $this->persister->getInsertSQL();
  150.     }
  151.     /**
  152.      * {@inheritdoc}
  153.      */
  154.     public function getResultSetMapping()
  155.     {
  156.         return $this->persister->getResultSetMapping();
  157.     }
  158.     /**
  159.      * {@inheritdoc}
  160.      */
  161.     public function getSelectConditionStatementSQL($field$value$assoc null$comparison null)
  162.     {
  163.         return $this->persister->getSelectConditionStatementSQL($field$value$assoc$comparison);
  164.     }
  165.     /**
  166.      * {@inheritdoc}
  167.      */
  168.     public function exists($entityCriteria $extraConditions null)
  169.     {
  170.         if (null === $extraConditions) {
  171.             $key = new EntityCacheKey($this->class->rootEntityName$this->class->getIdentifierValues($entity));
  172.             if ($this->region->contains($key)) {
  173.                 return true;
  174.             }
  175.         }
  176.         return $this->persister->exists($entity$extraConditions);
  177.     }
  178.     /**
  179.      * {@inheritdoc}
  180.      */
  181.     public function getCacheRegion()
  182.     {
  183.         return $this->region;
  184.     }
  185.     /**
  186.      * @return \Doctrine\ORM\Cache\EntityHydrator
  187.      */
  188.     public function getEntityHydrator()
  189.     {
  190.         return $this->hydrator;
  191.     }
  192.     /**
  193.      * {@inheritdoc}
  194.      */
  195.     public function storeEntityCache($entityEntityCacheKey $key)
  196.     {
  197.         $class      $this->class;
  198.         $className  ClassUtils::getClass($entity);
  199.         if ($className !== $this->class->name) {
  200.             $class $this->metadataFactory->getMetadataFor($className);
  201.         }
  202.         $entry  $this->hydrator->buildCacheEntry($class$key$entity);
  203.         $cached $this->region->put($key$entry);
  204.         if ($this->cacheLogger && $cached) {
  205.             $this->cacheLogger->entityCachePut($this->regionName$key);
  206.         }
  207.         return $cached;
  208.     }
  209.     /**
  210.      * @param object $entity
  211.      */
  212.     private function storeJoinedAssociations($entity)
  213.     {
  214.         if ($this->joinedAssociations === null) {
  215.             $associations = [];
  216.             foreach ($this->class->associationMappings as $name => $assoc) {
  217.                 if (isset($assoc['cache']) &&
  218.                     ($assoc['type'] & ClassMetadata::TO_ONE) &&
  219.                     ($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ! $assoc['isOwningSide'])) {
  220.                     $associations[] = $name;
  221.                 }
  222.             }
  223.             $this->joinedAssociations $associations;
  224.         }
  225.         foreach ($this->joinedAssociations as $name) {
  226.             $assoc       $this->class->associationMappings[$name];
  227.             $assocEntity $this->class->getFieldValue($entity$name);
  228.             if ($assocEntity === null) {
  229.                 continue;
  230.             }
  231.             $assocId        $this->uow->getEntityIdentifier($assocEntity);
  232.             $assocMetadata  $this->metadataFactory->getMetadataFor($assoc['targetEntity']);
  233.             $assocKey       = new EntityCacheKey($assocMetadata->rootEntityName$assocId);
  234.             $assocPersister $this->uow->getEntityPersister($assoc['targetEntity']);
  235.             $assocPersister->storeEntityCache($assocEntity$assocKey);
  236.         }
  237.     }
  238.     /**
  239.      * Generates a string of currently query
  240.      *
  241.      * @param string            $query
  242.      * @param string[]|Criteria $criteria
  243.      * @param string[]          $orderBy
  244.      * @param int               $limit
  245.      * @param int               $offset
  246.      *
  247.      * @return string
  248.      */
  249.     protected function getHash($query$criteria, array $orderBy null$limit null$offset null)
  250.     {
  251.         [$params] = $criteria instanceof Criteria
  252.             $this->persister->expandCriteriaParameters($criteria)
  253.             : $this->persister->expandParameters($criteria);
  254.         return sha1($query serialize($params) . serialize($orderBy) . $limit $offset);
  255.     }
  256.     /**
  257.      * {@inheritdoc}
  258.      */
  259.     public function expandParameters($criteria)
  260.     {
  261.         return $this->persister->expandParameters($criteria);
  262.     }
  263.     /**
  264.      * {@inheritdoc}
  265.      */
  266.     public function expandCriteriaParameters(Criteria $criteria)
  267.     {
  268.         return $this->persister->expandCriteriaParameters($criteria);
  269.     }
  270.     /**
  271.      * {@inheritdoc}
  272.      */
  273.     public function getClassMetadata()
  274.     {
  275.         return $this->persister->getClassMetadata();
  276.     }
  277.     /**
  278.      * {@inheritdoc}
  279.      */
  280.     public function getManyToManyCollection(array $assoc$sourceEntity$offset null$limit null)
  281.     {
  282.         return $this->persister->getManyToManyCollection($assoc$sourceEntity$offset$limit);
  283.     }
  284.     /**
  285.      * {@inheritdoc}
  286.      */
  287.     public function getOneToManyCollection(array $assoc$sourceEntity$offset null$limit null)
  288.     {
  289.         return $this->persister->getOneToManyCollection($assoc$sourceEntity$offset$limit);
  290.     }
  291.     /**
  292.      * {@inheritdoc}
  293.      */
  294.     public function getOwningTable($fieldName)
  295.     {
  296.         return $this->persister->getOwningTable($fieldName);
  297.     }
  298.     /**
  299.      * {@inheritdoc}
  300.      */
  301.     public function executeInserts()
  302.     {
  303.         $this->queuedCache['insert'] = $this->persister->getInserts();
  304.         return $this->persister->executeInserts();
  305.     }
  306.     /**
  307.      * {@inheritdoc}
  308.      */
  309.     public function load(array $criteria$entity null$assoc null, array $hints = [], $lockMode null$limit null, array $orderBy null)
  310.     {
  311.         if ($entity !== null || $assoc !== null || ! empty($hints) || $lockMode !== null) {
  312.             return $this->persister->load($criteria$entity$assoc$hints$lockMode$limit$orderBy);
  313.         }
  314.         //handle only EntityRepository#findOneBy
  315.         $query      $this->persister->getSelectSQL($criterianullnull$limitnull$orderBy);
  316.         $hash       $this->getHash($query$criterianullnullnull);
  317.         $rsm        $this->getResultSetMapping();
  318.         $queryKey   = new QueryCacheKey($hash0Cache::MODE_NORMAL$this->timestampKey);
  319.         $queryCache $this->cache->getQueryCache($this->regionName);
  320.         $result     $queryCache->get($queryKey$rsm);
  321.         if ($result !== null) {
  322.             if ($this->cacheLogger) {
  323.                 $this->cacheLogger->queryCacheHit($this->regionName$queryKey);
  324.             }
  325.             return $result[0];
  326.         }
  327.         if (($result $this->persister->load($criteria$entity$assoc$hints$lockMode$limit$orderBy)) === null) {
  328.             return null;
  329.         }
  330.         $cached $queryCache->put($queryKey$rsm, [$result]);
  331.         if ($this->cacheLogger) {
  332.             if ($result) {
  333.                 $this->cacheLogger->queryCacheMiss($this->regionName$queryKey);
  334.             }
  335.             if ($cached) {
  336.                 $this->cacheLogger->queryCachePut($this->regionName$queryKey);
  337.             }
  338.         }
  339.         return $result;
  340.     }
  341.     /**
  342.      * {@inheritdoc}
  343.      */
  344.     public function loadAll(array $criteria = [], array $orderBy null$limit null$offset null)
  345.     {
  346.         $query      $this->persister->getSelectSQL($criterianullnull$limit$offset$orderBy);
  347.         $hash       $this->getHash($query$criterianullnullnull);
  348.         $rsm        $this->getResultSetMapping();
  349.         $queryKey   = new QueryCacheKey($hash0Cache::MODE_NORMAL$this->timestampKey);
  350.         $queryCache $this->cache->getQueryCache($this->regionName);
  351.         $result     $queryCache->get($queryKey$rsm);
  352.         if ($result !== null) {
  353.             if ($this->cacheLogger) {
  354.                 $this->cacheLogger->queryCacheHit($this->regionName$queryKey);
  355.             }
  356.             return $result;
  357.         }
  358.         $result $this->persister->loadAll($criteria$orderBy$limit$offset);
  359.         $cached $queryCache->put($queryKey$rsm$result);
  360.         if ($this->cacheLogger) {
  361.             if ($result) {
  362.                 $this->cacheLogger->queryCacheMiss($this->regionName$queryKey);
  363.             }
  364.             if ($cached) {
  365.                 $this->cacheLogger->queryCachePut($this->regionName$queryKey);
  366.             }
  367.         }
  368.         return $result;
  369.     }
  370.     /**
  371.      * {@inheritdoc}
  372.      */
  373.     public function loadById(array $identifier$entity null)
  374.     {
  375.         $cacheKey   = new EntityCacheKey($this->class->rootEntityName$identifier);
  376.         $cacheEntry $this->region->get($cacheKey);
  377.         $class      $this->class;
  378.         if ($cacheEntry !== null) {
  379.             if ($cacheEntry->class !== $this->class->name) {
  380.                 $class $this->metadataFactory->getMetadataFor($cacheEntry->class);
  381.             }
  382.             $cachedEntity $this->hydrator->loadCacheEntry($class$cacheKey$cacheEntry$entity);
  383.             if ($cachedEntity !== null) {
  384.                 if ($this->cacheLogger) {
  385.                     $this->cacheLogger->entityCacheHit($this->regionName$cacheKey);
  386.                 }
  387.                 return $cachedEntity;
  388.             }
  389.         }
  390.         $entity $this->persister->loadById($identifier$entity);
  391.         if ($entity === null) {
  392.             return null;
  393.         }
  394.         $class      $this->class;
  395.         $className  ClassUtils::getClass($entity);
  396.         if ($className !== $this->class->name) {
  397.             $class $this->metadataFactory->getMetadataFor($className);
  398.         }
  399.         $cacheEntry $this->hydrator->buildCacheEntry($class$cacheKey$entity);
  400.         $cached     $this->region->put($cacheKey$cacheEntry);
  401.         if ($cached && (null === $this->joinedAssociations || $this->joinedAssociations)) {
  402.             $this->storeJoinedAssociations($entity);
  403.         }
  404.         if ($this->cacheLogger) {
  405.             if ($cached) {
  406.                 $this->cacheLogger->entityCachePut($this->regionName$cacheKey);
  407.             }
  408.             $this->cacheLogger->entityCacheMiss($this->regionName$cacheKey);
  409.         }
  410.         return $entity;
  411.     }
  412.     /**
  413.      * {@inheritDoc}
  414.      */
  415.     public function count($criteria = [])
  416.     {
  417.         return $this->persister->count($criteria);
  418.     }
  419.     /**
  420.      * {@inheritdoc}
  421.      */
  422.     public function loadCriteria(Criteria $criteria)
  423.     {
  424.         $orderBy     $criteria->getOrderings();
  425.         $limit       $criteria->getMaxResults();
  426.         $offset      $criteria->getFirstResult();
  427.         $query       $this->persister->getSelectSQL($criteria);
  428.         $hash        $this->getHash($query$criteria$orderBy$limit$offset);
  429.         $rsm         $this->getResultSetMapping();
  430.         $queryKey    = new QueryCacheKey($hash0Cache::MODE_NORMAL$this->timestampKey);
  431.         $queryCache  $this->cache->getQueryCache($this->regionName);
  432.         $cacheResult $queryCache->get($queryKey$rsm);
  433.         if ($cacheResult !== null) {
  434.             if ($this->cacheLogger) {
  435.                 $this->cacheLogger->queryCacheHit($this->regionName$queryKey);
  436.             }
  437.             return $cacheResult;
  438.         }
  439.         $result $this->persister->loadCriteria($criteria);
  440.         $cached $queryCache->put($queryKey$rsm$result);
  441.         if ($this->cacheLogger) {
  442.             if ($result) {
  443.                 $this->cacheLogger->queryCacheMiss($this->regionName$queryKey);
  444.             }
  445.             if ($cached) {
  446.                 $this->cacheLogger->queryCachePut($this->regionName$queryKey);
  447.             }
  448.         }
  449.         return $result;
  450.     }
  451.     /**
  452.      * {@inheritdoc}
  453.      */
  454.     public function loadManyToManyCollection(array $assoc$sourceEntityPersistentCollection $collection)
  455.     {
  456.         $persister $this->uow->getCollectionPersister($assoc);
  457.         $hasCache  = ($persister instanceof CachedPersister);
  458.         if ( ! $hasCache) {
  459.             return $this->persister->loadManyToManyCollection($assoc$sourceEntity$collection);
  460.         }
  461.         $ownerId $this->uow->getEntityIdentifier($collection->getOwner());
  462.         $key     $this->buildCollectionCacheKey($assoc$ownerId);
  463.         $list    $persister->loadCollectionCache($collection$key);
  464.         if ($list !== null) {
  465.             if ($this->cacheLogger) {
  466.                 $this->cacheLogger->collectionCacheHit($persister->getCacheRegion()->getName(), $key);
  467.             }
  468.             return $list;
  469.         }
  470.         $list $this->persister->loadManyToManyCollection($assoc$sourceEntity$collection);
  471.         $persister->storeCollectionCache($key$list);
  472.         if ($this->cacheLogger) {
  473.             $this->cacheLogger->collectionCacheMiss($persister->getCacheRegion()->getName(), $key);
  474.         }
  475.         return $list;
  476.     }
  477.     /**
  478.      * {@inheritdoc}
  479.      */
  480.     public function loadOneToManyCollection(array $assoc$sourceEntityPersistentCollection $collection)
  481.     {
  482.         $persister $this->uow->getCollectionPersister($assoc);
  483.         $hasCache  = ($persister instanceof CachedPersister);
  484.         if ( ! $hasCache) {
  485.             return $this->persister->loadOneToManyCollection($assoc$sourceEntity$collection);
  486.         }
  487.         $ownerId $this->uow->getEntityIdentifier($collection->getOwner());
  488.         $key     $this->buildCollectionCacheKey($assoc$ownerId);
  489.         $list    $persister->loadCollectionCache($collection$key);
  490.         if ($list !== null) {
  491.             if ($this->cacheLogger) {
  492.                 $this->cacheLogger->collectionCacheHit($persister->getCacheRegion()->getName(), $key);
  493.             }
  494.             return $list;
  495.         }
  496.         $list $this->persister->loadOneToManyCollection($assoc$sourceEntity$collection);
  497.         $persister->storeCollectionCache($key$list);
  498.         if ($this->cacheLogger) {
  499.             $this->cacheLogger->collectionCacheMiss($persister->getCacheRegion()->getName(), $key);
  500.         }
  501.         return $list;
  502.     }
  503.     /**
  504.      * {@inheritdoc}
  505.      */
  506.     public function loadOneToOneEntity(array $assoc$sourceEntity, array $identifier = [])
  507.     {
  508.         return $this->persister->loadOneToOneEntity($assoc$sourceEntity$identifier);
  509.     }
  510.     /**
  511.      * {@inheritdoc}
  512.      */
  513.     public function lock(array $criteria$lockMode)
  514.     {
  515.         $this->persister->lock($criteria$lockMode);
  516.     }
  517.     /**
  518.      * {@inheritdoc}
  519.      */
  520.     public function refresh(array $id$entity$lockMode null)
  521.     {
  522.         $this->persister->refresh($id$entity$lockMode);
  523.     }
  524.     /**
  525.      * @param array $association
  526.      * @param array $ownerId
  527.      *
  528.      * @return CollectionCacheKey
  529.      */
  530.     protected function buildCollectionCacheKey(array $association$ownerId)
  531.     {
  532.         /** @var ClassMetadata $metadata */
  533.         $metadata $this->metadataFactory->getMetadataFor($association['sourceEntity']);
  534.         return new CollectionCacheKey($metadata->rootEntityName$association['fieldName'], $ownerId);
  535.     }
  536. }