2013-03-27 6 views
8

Sto combattendo con questo problema un sacco di tempo e ho trovato, che ufficialmente, ho potuto memorizzare solo alcune query personalizzate (useResultCache (true) sull'oggetto Query). Ma ho bisogno di memorizzare tutte le query nella mia applicazione su una tabella. Che dire dei metodi find * su EntityManager? ...Doctrine 2 e ORM: come memorizzare ogni query per qualche entità?

Qualcuno potrebbe aiutarmi a trovare una soluzione elegante?

risposta

12

Questo non è ancora supportato e dovresti eventualmente gestirlo nel tuo livello di servizio o nei tuoi repository estesi.

Quello che stai cercando è il second level cache as in Hibernate, che in pratica ti permette di collegare un archivio di valori-chiave come redis, riak, mongodb, ecc per rendere le cose incredibilmente veloci quando le operazioni sono semplici operazioni di recupero.

È in corso una richiesta di estrazione in corso al numero https://github.com/doctrine/doctrine2/pull/580, che probabilmente verrà inoltrata in Doctrine ORM 2.5, quindi rivedere quella.

use Doctrine\ORM\EntityRepository; 
use Doctrine\ORM\EntityManager; 
use Doctrine\Common\Cache\Cache; 
use Doctrine\Common\Cache\ArrayCache; 

class MyBaseRepo extends EntityRepository 
{ 
    public function __construct(EntityManager $entityManager) 
    { 
     parent::__construct($entityManager); 
     $cache  = $em->getConfiguration()->getHydrationCache(); 
     $this->cache = $cache ?: new ArrayCache(); 
    } 

    public function find($id) 
    { 
     if (!$object = $this->tryFetchFromCache($id)) { 
      $object = parent::find($id); 
      $this->cache->save($this->generateKey($id), $object); 
     } 

     return $object; 
    } 

    protected function tryFetchFromCache($id) 
    { 
     if (!$object = $this->cache->fetch($this->generateCacheKey($id))) { 
      return null; 
     } 

     return $this->getEntityManager()->merge($object); 
    } 

    public function generateCacheKey($id) { /* ... */ } 
} 

È possibile forzare questo per essere il repository di base per l'ORM nella configurazione mentre bootstrapping la vostra applicazione:

$configuration = new \Doctrine\ORM\Configuration(); 

$configuration->setDefaultRepositoryClassName('My\MyBaseRepo'); 

Questo ti costringe anche di eliminare le voci della cache quando un aggiornamento/salva accade per qualsiasi delle entità:

use Doctrine\Common\EventSubscriber; 
use Doctrine\ORM\Event\OnFlushEventArgs; 
use Doctrine\ORM\Events; 

class IssueUpdateSubscriber implements EventSubscriber 
{ 
    public function onFlush(OnFlushEventArgs $args) 
    { 
     $em = $args->getEntityManager(); 
     $uow = $em->getUnitOfWork(); 

     if (!$cache = $em->getConfiguration()->getHydrationCache()) { 
      return; 
     } 

     $busted = array_merge(
      $uow->getScheduledEntityUpdates(), 
      $uow->getScheduledEntityDeletions(), 
     ); 

     foreach ($busted as $entityToClear) { 
      $className = get_class($entityToClear); 
      $metadata = $em->getClassMetadata($className); 
      $repository = $em->getRepository($className); 
      $id   = $metadata->getIdentifierValues($entityToClear); 

      $cache->delete($repository->generateCacheKey($id)); 
     } 
    } 

    public function getSubscribedEvents() 
    { 
     return array(Events::onFlush); 
    } 
} 

Si noti che questa implementazione NON intercetta tutti gli accessi al proprio database per una data entità. Non intercetterà l'inizializzazione del caricamento pigro causata dai proxy, ed è molto fragile, quindi per favore installa alcuni test di integrazione adeguati per supportarlo.

+1

Grazie per la risposta! Potresti, per favore, mostrarmi il modo migliore per memorizzare le entità pigre caricate? Sarò apprezzato per questo :) –

+0

@AndriiVasyliev che non può essere fatto, è per questo che ti ho detto di guardare quella richiesta pull. – Ocramius

+0

Ok, ho capito. Grazie per il tuo aiuto! –

Problemi correlati