/**
  * Generate the ESI block
  *
  * @param  Varien_Object $esiData
  * @return Mage_Core_Block_Template|null
  */
 protected function _getEsiBlock($esiData)
 {
     $block = null;
     Varien_Profiler::start('turpentine::controller::esi::_getEsiBlock');
     foreach ($esiData->getSimpleRegistry() as $key => $value) {
         Mage::register($key, $value, true);
     }
     foreach ($esiData->getComplexRegistry() as $key => $data) {
         $value = Mage::getModel($data['model']);
         if (!is_object($value)) {
             Mage::helper('turpentine/debug')->logWarn('Failed to register key/model: %s as %s(%s)', $key, $data['model'], $data['id']);
             continue;
         } else {
             $value->load($data['id']);
             Mage::register($key, $value, true);
         }
     }
     $layout = Mage::getSingleton('core/layout');
     // dispatch event for adding handles to layout update
     Mage::dispatchEvent('controller_action_layout_load_before', array('action' => $this, 'layout' => $layout));
     $layoutUpdate = $layout->getUpdate();
     $layoutUpdate->load($this->_swapCustomerHandles($esiData->getLayoutHandles()));
     foreach ($esiData->getDummyBlocks() as $blockName) {
         $layout->createBlock('Mage_Core_Block_Template', $blockName);
     }
     if (!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
         Mage::dispatchEvent('controller_action_layout_generate_xml_before', array('action' => $this, 'layout' => $layout));
     }
     $layout->generateXml();
     /** @var Nexcessnet_Turpentine_Helper_Data $turpentineHelper */
     $turpentineHelper = Mage::helper('turpentine/data')->setLayout($layout);
     $blockNode = current($layout->getNode()->xpath(sprintf('//block[@name=\'%s\']', $esiData->getNameInLayout())));
     if (!$blockNode instanceof Mage_Core_Model_Layout_Element) {
         Mage::helper('turpentine/debug')->logWarn('No block node found with @name="%s"', $esiData->getNameInLayout());
         return null;
     }
     $nodesToGenerate = $turpentineHelper->getChildBlockNames($blockNode);
     Mage::getModel('turpentine/shim_mage_core_layout')->shim_generateFullBlock($blockNode);
     //find addional blocks that aren't defined in the <block/> but via <reference name="%s">
     $referenceNodes = $layout->getNode()->xpath(sprintf('//reference[@name=\'%s\']', $esiData->getNameInLayout()));
     if ($referenceNodes) {
         foreach ($referenceNodes as $referenceNode) {
             if ($referenceNode instanceof Mage_Core_Model_Layout_Element) {
                 $referencesToGenerate = $turpentineHelper->getChildBlockNames($referenceNode);
                 $nodesToGenerate = array_merge($nodesToGenerate, $referencesToGenerate);
             }
         }
     }
     // dispatch event for adding xml layout elements
     if (!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
         Mage::dispatchEvent('controller_action_layout_generate_blocks_before', array('action' => $this, 'layout' => $layout));
     }
     foreach (array_unique($nodesToGenerate) as $nodeName) {
         foreach ($layout->getNode()->xpath(sprintf('//reference[@name=\'%s\']', $nodeName)) as $node) {
             $layout->generateBlocks($node);
         }
     }
     $block = $layout->getBlock($esiData->getNameInLayout());
     if (!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
         Mage::dispatchEvent('controller_action_layout_generate_blocks_after', array('action' => $this, 'layout' => $layout));
     }
     $this->_isLayoutLoaded = true;
     Varien_Profiler::stop('turpentine::controller::esi::_getEsiBlock');
     return $block;
 }
Example #2
0
 protected function _watch($observer)
 {
     $block = $observer->getBlock();
     if ($this->_isUnwantedBlock($block)) {
         return;
     }
     $style = ' [style=solid]';
     $parent = $block->getParentBlock();
     $name_block = $block->getNameInLayout();
     $name_parent = 'unknown';
     $this->_checkAssumptions($parent, $block);
     if ($this->_isParentlessAnonymous($parent, $block)) {
         $style = ' [style=dashed]';
         $parent = new Varien_Object();
         $parent->setNameInLayout($this->_getAssumedParentNameFromStack());
         $name_parent = $parent->getNameInLayout();
     } else {
         if ($this->_isAssumeParentAndRealParentMismatch($parent, $block)) {
             $style = ' [style=dotted]';
             $parent = new Varien_Object();
             $parent->setNameInLayout($this->_getAssumedParentNameFromStack());
             $name_parent = $parent->getNameInLayout();
         } else {
             if ($this->_isGoofyFacade($parent, $block)) {
                 $style = ' [style=dotted]';
                 $parent = new Varien_Object();
                 $parent->setNameInLayout($this->_getAssumedParentNameFromStack());
                 $name_parent = $parent->getNameInLayout();
             } else {
                 if (is_object($parent)) {
                     $name_parent = $parent->getNameInLayout();
                 }
             }
         }
     }
     if (!$parent) {
         self::$_graphs[] = '"' . $block->getNameInLayout() . '"' . $style;
     } else {
         self::$_graphs[] = '"' . $parent->getNameInLayout() . '"' . '->' . '"' . $block->getNameInLayout() . '"' . $style;
     }
     $template = $block->getTemplate() ? $block->getTemplate() : 'NO TEMPLATE';
     $definition = '"' . $name_block . '"' . '[label="' . $name_block . '\\\\n' . get_class($block) . '\\\\n' . $template . '"]';
     self::$_definitions[$name_block] = $definition;
 }
 /**
  * Generate the ESI block
  *
  * @param  Varien_Object $esiData
  * @return Mage_Core_Block_Template
  */
 protected function _getEsiBlock($esiData)
 {
     $block = null;
     Varien_Profiler::start('turpentine::controller::esi::_getEsiBlock');
     foreach ($esiData->getSimpleRegistry() as $key => $value) {
         Mage::register($key, $value, true);
     }
     foreach ($esiData->getComplexRegistry() as $key => $data) {
         $value = Mage::getModel($data['model']);
         if (!is_object($value)) {
             Mage::helper('turpentine/debug')->logWarn('Failed to register key/model: %s as %s(%s)', $key, $data['model'], $data['id']);
             continue;
         } else {
             $value->load($data['id']);
             Mage::register($key, $value, true);
         }
     }
     $layout = Mage::getSingleton('core/layout');
     Mage::getSingleton('core/design_package')->setPackageName($esiData->getDesignPackage())->setTheme($esiData->getDesignTheme());
     $layoutUpdate = $layout->getUpdate();
     $layoutUpdate->load($this->_swapCustomerHandles($esiData->getLayoutHandles()));
     foreach ($esiData->getDummyBlocks() as $blockName) {
         $layout->createBlock('Mage_Core_Block_Template', $blockName);
     }
     $layout->generateXml();
     $blockNode = current($layout->getNode()->xpath(sprintf('//block[@name=\'%s\']', $esiData->getNameInLayout())));
     if ($blockNode instanceof Varien_Simplexml_Element) {
         $nodesToGenerate = Mage::helper('turpentine/data')->setLayout($layout)->getChildBlockNames($blockNode);
         Mage::getModel('turpentine/shim_mage_core_layout')->shim_generateFullBlock($blockNode);
         foreach ($nodesToGenerate as $nodeName) {
             foreach ($layout->getNode()->xpath(sprintf('//reference[@name=\'%s\']', $nodeName)) as $node) {
                 $layout->generateBlocks($node);
             }
         }
         $block = $layout->getBlock($esiData->getNameInLayout());
     } else {
         Mage::helper('turpentine/debug')->logWarn('No block node found with @name="%s"', $esiData->getNameInLayout());
     }
     Varien_Profiler::stop('turpentine::controller::esi::_getEsiBlock');
     return $block;
 }
Example #4
0
 /**
  * Called on 
  * 	core_block_abstract_to_html_before
  *
  * Checks if the "esi" variable is set on a block.
  * 	If yes, the template of the block is replaced by varnish/esi.phtml which contains the <esi:include> tag
  * 	it also adds to the response the header X-magento-doesi which will be interpreted by varnish and tell it to do the esi processing
  * 
  * @param array $eventObject
  */
 public function injectEsi($eventObject)
 {
     //No ESI injection if the module is disabled or the request is made on HTTPS
     if (!Mage::helper('varnish')->isVarnishModuleEnabled() || Mage::app()->getRequest()->isSecure()) {
         return;
     }
     $block = $eventObject->getBlock();
     if ($block instanceof Mage_Core_Block_Template) {
         $esi = $block->getEsi();
         if ($esi == true) {
             //We don't allow ESI in admin, for now. Maybe in future releases.
             if (Mage::app()->getStore()->getCode() == 'admin') {
                 throw new Mage_Adminhtml_Exception("ESI includes are forbidden in Admin");
             }
             // We replace the template of the block by the varnish/esi.phtml template
             // The HTML of our template will replace the real HTML of the block
             $block->setTemplate('varnish/esi.phtml');
             $src = new Varien_Object();
             //Blocks change depending on the store id, so we keep track of that
             $src->setStoreId(Mage::app()->getStore()->getId());
             //Blocks also change depending on the design so we keep track of the package and the theme of the current block
             $src->setDesignPackage(Mage::getDesign()->getPackageName());
             $src->setDesignTheme(Mage::getDesign()->getTheme('layout'));
             $src->setNameInLayout($block->getNameInLayout());
             /*
              * Set the cache type
              * 	per-client
              *  per-page
              * 	global
              *
              * 
              * per-client tells varnish to cache the block per-client basis.
              * per-page tells varnish to cache the content based on the url of the page.
              * global tells varnish to serve the same cached version to every client.
              * 
              * The per-client cache is based on the frontend cookie of the client.
              * 
              * We default the cache type to "global"
              */
             if (empty($esi['cache_type'])) {
                 $esi['cache_type'] = 'global';
             }
             $src->setCacheType($esi['cache_type']);
             /**
              *	If the block is cached on a per-page basis
              *	we create an entry in our ESI table to keep track the URLs where the block appear
              *	 
              */
             if ($src->getCacheType() === 'per-page') {
                 $parentUrl = Mage::app()->getRequest()->getRequestString();
                 $src->setParentUrl($parentUrl);
             }
             /**
              * Expiry (or TTL in Varnish lingo). How lon will the object be stored in Varnish?
              * TODO: make sure the expiry is in format 1d 24h 1140m 86400s
              */
             if (!empty($esi['expiry'])) {
                 $src->setExpiry($esi['expiry']);
             } else {
                 if ($src->getCacheType() === 'per-client') {
                     $src->setExpiry(Mage::getStoreConfig('varnish/cache/per_client_default_expiry'));
                 } else {
                     if ($src->getCacheType() === 'per-page') {
                         $src->setExpiry(Mage::getStoreConfig('varnish/cache/per_page_default_expiry'));
                     } else {
                         $src->setExpiry(Mage::getStoreConfig('varnish/cache/global_default_expiry'));
                     }
                 }
             }
             //We create a unique fingerprint with all our values
             foreach ($src->getData() as $value) {
                 $this->_hash($value);
             }
             // $src is the source for our <esi:include> it is composed of all the above variables
             $src->setUrl("/varnish/cache/getBlock/cachetype/{$src->getCacheType()}/expiry/{$src->getExpiry()}/fingerprint/{$this->_hash()}");
             /**
              * Registry save:
              * 	some block rely on values stored in the Mage::registry().
              * 	For example, the product page relies on Mage::registry('current_product');
              *  The problem is that the Mage::registry is not persistent between requests. This means that once the request is served,
              *  the registry looses its data.
              *  This means that when Varnish makes the ESI request, the registry is empty and if the block makes a call to Mage::registry('current_product')
              *  the function will return null.
              *  In order to strive this problem, when you setEsi on a block using the mage registry, you need to specify in the layout which keys you want to keep.
              *  These keys will be saved in the magento cache and thus be accessible when the ESI request is made
              */
             if (!empty($esi['registry_keys'])) {
                 // We create an array with the <registry_keys></registry_keys> set in the layout
                 $registryKeys = explode(',', $esi['registry_keys']);
                 // We iterate through each of the registrykey...
                 foreach ($registryKeys as $registryKey) {
                     $registryContent = Mage::registry($registryKey);
                     if ($registryContent !== null) {
                         // If the key exist we save the content in an array
                         $registry[] = array("key" => $registryKey, "content" => $registryContent);
                     }
                 }
                 $src->setRegistry($registry);
             }
             $src->setBlockType(get_class($block));
             // and we save the content in the cache with the hash as the id
             $cache = Mage::helper('varnish')->getRedisCache();
             $tags = array("VARNISH_CACHETYPE_{$src->getCacheType()}", "VARNISH_BLOCKTYPE_{$src->getBlockType()}", "VARNISH_BLOCKNAME_{$src->getNameInLayout()}");
             $cache->save(serialize($src), $this->_hash(), $tags, null);
             $block->setSrc($src);
             // Tell varnish to do esi processing on the page
             Mage::getSingleton('varnish/cache')->setDoEsi(true);
         }
     }
 }