Last active
August 29, 2015 14:08
-
-
Save dbu/67c838a2002ff667eacb to your computer and use it in GitHub Desktop.
CMF FOSHttpCache integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Symfony\Cmf\CoreBundle\Listener; | |
use Doctrine\Common\EventSubscriber; | |
use Doctrine\Common\Persistence\Event\LifecycleEventArgs; | |
use Symfony\Cmf\CoreBundle\Cache\CmsInvalidator; | |
/** | |
* Doctrine listener to invalidate cached urls on changes. | |
*/ | |
class CacheInvalidationSubscriber implements EventSubscriber | |
{ | |
/** | |
* @var CmsInvalidator | |
*/ | |
private $invalidator; | |
public function __construct(CmsInvalidator $invalidator) | |
{ | |
$this->invalidator = $invalidator; | |
} | |
public function getSubscribedEvents() | |
{ | |
return array( | |
'postCreate', | |
'postUpdate', | |
); | |
} | |
/** | |
* We care about newly created objects as they could have an impact on their parents. | |
* | |
* @param LifecycleEventArgs $e | |
*/ | |
public function postCreate(LifecycleEventArgs $e) | |
{ | |
$this->invalidator->invalidateObject($e->getObjectManager(), $e->getObject()); | |
} | |
public function postUpdate(LifecycleEventArgs $e) | |
{ | |
$this->invalidator->invalidateObject($e->getObjectManager(), $e->getObject()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Symfony\Cmf\CoreBundle\Command; | |
use Doctrine\Common\Util\ClassUtils; | |
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; | |
use Symfony\Component\Console\Input\InputInterface; | |
use Symfony\Component\Console\Input\InputOption; | |
use Symfony\Component\Console\Output\OutputInterface; | |
/** | |
* Command to trigger cache invalidation because of publish workflow. | |
*/ | |
class CheckCacheCommand extends ContainerAwareCommand | |
{ | |
public function configure() | |
{ | |
$this | |
->setName('cmf:check-cache') | |
->setDescription('Invalidate cached pages that changed their published status') | |
->addOption('since', null, InputOption::VALUE_OPTIONAL, 'Timestamp for content to invalidate, any php date string is accepted', '1 day ago') | |
; | |
} | |
public function execute(InputInterface $input, OutputInterface $output) | |
{ | |
$timestamp = new \DateTime($input->getOption('since')); | |
$registry = $this->getContainer()->get('doctrine_phpcr'); | |
$invalidator = $this->getContainer()->get('cmf_core.cache.cms_invalidator'); | |
$changeFinder = $this->getContainer()->get('cmf_core.publish_workflow.change_finder'); | |
$changedDocuments = $changeFinder->findChangedDocuments($timestamp); | |
foreach ($changedDocuments as $document) { | |
$dm = $registry->getManagerForClass(ClassUtils::getClass($document)); | |
$invalidator->invalidateObject($dm, $document); | |
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { | |
$output->writeln(sprintf('Invalidating %s', $dm->getUnitOfWork()->getDocumentId($document))); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Symfony\Cmf\Bundle\CoreBundle\Cache; | |
use Doctrine\ODM\PHPCR\DocumentManager; | |
use FOS\HttpCacheBundle\CacheManager; | |
use Liipch\CoreBundle\Document\HeaderContainer; | |
use Liipch\NewsBundle\Document\NewsItem; | |
use PHPCR\Util\PathHelper; | |
use Symfony\Cmf\Bundle\MenuBundle\Model\MenuNodeBase; | |
use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route; | |
use Symfony\Cmf\Component\Routing\RouteReferrersReadInterface; | |
/** | |
* Handle cache invalidation for objects. | |
*/ | |
class CmsInvalidator | |
{ | |
/** | |
* @var CacheManager | |
*/ | |
private $cm; | |
public function __construct(CacheManager $cm) | |
{ | |
$this->cm = $cm; | |
} | |
/** | |
* @param DocumentManager $dm The document manager responsible for this object. | |
* @param object $o A managed object to invalidate with varnish. | |
*/ | |
public function invalidateObject(DocumentManager $dm, $o) | |
{ | |
switch ($o) { | |
case $o instanceof Route: | |
$this->cm->refreshRoute($o); | |
break; | |
case $o instanceof RouteReferrersReadInterface: | |
foreach ($o->getRoutes() as $route) { | |
$this->cm->invalidateRoute($route); | |
} | |
// this is specific to my project, but left in here to show a possible usecase | |
if ($o instanceof NewsItem) { | |
foreach (array('de', 'fr', 'en') as $lang) { | |
$this->cm->invalidateRoute("/cms/routes/$lang/news"); | |
} | |
$this->refreshHome(); | |
} | |
break; | |
case $o instanceof MenuNodeBase: | |
$this->cm->invalidateRegex('.*'); | |
break; | |
// this is specific to my project, but left in here to show a possible usecase | |
case $o instanceof HeaderContainer: | |
$this->cm->invalidateRegex('.*'); | |
break; | |
// should use ESI for headers | |
default: | |
$this->invalidateParent($dm, $o); | |
break; | |
} | |
} | |
private function invalidateParent(DocumentManager $dm, $o) | |
{ | |
$parentPath = PathHelper::getParentPath($dm->getUnitOfWork()->getDocumentId($o)); | |
if ('/' === $parentPath) { | |
return; | |
} | |
$this->invalidateObject($dm, $dm->find(null, $parentPath)); | |
} | |
private function refreshHome() | |
{ | |
foreach (array('de', 'fr', 'en') as $lang) { | |
$this->cm->invalidateRoute("/cms/routes/$lang"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# needs to be loaded only when enabled, and rewritten to xml configuration | |
services: | |
cmf_core.cache.cms_invalidator: | |
class: Symfony\Cmf\CoreBundle\Cache\CmsInvalidator | |
arguments: | |
- @fos_http_cache.cache_manager | |
cmf_core.publish_workflow.change_finder: | |
class: Symfony\Cmf\CoreBundle\Cache\PublishWorkflowChangeFinder | |
arguments: | |
- @doctrine_phpcr.odm.document_manager | |
cmf_core.listener.cache_invalidation: | |
class: Symfony\Cmf\CoreBundle\Listener\CacheInvalidationSubscriber | |
arguments: | |
- @cmf_core.cache.cms_invalidator | |
tags: | |
- { name:"doctrine_phpcr.event_subscriber" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Symfony\Cmf\CoreBundle\Cache; | |
use Doctrine\ODM\PHPCR\DocumentManager; | |
use PHPCR\Query\QOM\QueryObjectModelConstantsInterface; | |
/** | |
* A helper service to query phpcr-odm for all documents that changed their | |
* publish status since a specified moment. | |
*/ | |
class PublishWorkflowChangeFinder | |
{ | |
/** | |
* @var DocumentManager | |
*/ | |
private $dm; | |
public function __construct(DocumentManager $dm) | |
{ | |
$this->dm = $dm; | |
} | |
/** | |
* Find all documents that changed their publication status due to the date | |
* based publish workflow fields. | |
* | |
* This method does *not* look at other recent changes like a changed | |
* publishable field. Use a doctrine listener to see active changes to | |
* documents. | |
* | |
* @param \DateTime $timestamp | |
* | |
* @return array The collection of all documents that changed their | |
* publication status since $timestamp | |
*/ | |
public function findChangedDocuments(\DateTime $timestamp) | |
{ | |
$queryBuilder = $this->dm->createPhpcrQueryBuilder(); | |
$qomf = $queryBuilder->qomf(); | |
$queryBuilder | |
->from($qomf->selector('u', 'nt:unstructured')) | |
->orWhere( | |
$qomf->andConstraint( | |
$qomf->comparison( | |
$qomf->propertyValue('u', 'publishStartDate'), | |
QueryObjectModelConstantsInterface::JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO, | |
$qomf->literal($timestamp) | |
), | |
$qomf->comparison( | |
$qomf->propertyValue('u', 'publishStartDate'), | |
QueryObjectModelConstantsInterface::JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO, | |
$qomf->literal(new \DateTime) | |
) | |
) | |
) | |
->orWhere( | |
$qomf->andConstraint( | |
$qomf->comparison( | |
$qomf->propertyValue('u', 'publishEndDate'), | |
QueryObjectModelConstantsInterface::JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO, | |
$qomf->literal($timestamp) | |
), | |
$qomf->comparison( | |
$qomf->propertyValue('u', 'publishEndDate'), | |
QueryObjectModelConstantsInterface::JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO, | |
$qomf->literal(new \DateTime) | |
) | |
) | |
) | |
; | |
return $this->dm->getDocumentsByPhpcrQuery($queryBuilder->getQuery()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment