Working with the http cache

A http cache is indispensable when a web app has reached a certain complexity or traffic. But caching also means that the data is probably not up to date when presenting it to website visitors. This post will show one way to bypass Shopware’s http cache for certain parts of a page.

To demonstrate, we will tackle a particular problem which caching is prone to: namely, not displaying user input. Data provided by a user after a cache is built cannot be displayed without rebuilding the cache. In this example I will show how to display, if a product is already saved on a customer’s note list.

For this, we  mainly need two things: a template extension and a controller.

We are extending the last block of the actions on the detail page. There we are using Shopware’s action tag to call our own controller with the module name, the controller name (that I called it KplngiOnNote) and the action of the controller (in this case, index). A controller called like this is being rendered without checking the http cache, which means it will display uncached data. We also pass the product ID, called articleID, to the controller. The code looks like this:

{extends file="parent:frontend/detail/actions.tpl"}

{block name='frontend_detail_actions_voucher'}
   {$smarty.block.parent}
   {action module=widgets controller=KplngiOnNote action=index productId=$sArticle.articleID}
{/block}

The rendered KplngiOnNote controller will be displayed from where it was called. In this case, after the action buttons.

The controller will check if the product of a detail page is already on a users note list, and then passes this information to the view. The code of the controller may look like this:

<?php

class Shopware_Controllers_Widgets_KplngiOnNote extends \Enlight_Controller_Action
{
   public function indexAction()
   {
       if ($this->isProductOnCustomersNote()) {
           $this->View()->assign('onNote', true);
       } else {
           $this->View()->assign('onNote', false);
       }
   }

   private function isProductOnCustomersNote()
   {
       $responseCookies = $this->front->Response()->getCookies();
       $productId = $this->Request()->getParam('productId');

       if (!$productId) {
           return false;
       }

       if (isset($responseCookies['sUniqueID']['value']) && $responseCookies['sUniqueID']['value']) {
           $uniqueId = $responseCookies['sUniqueID']['value'];
       } else {
           $uniqueId = $this->front->Request()->getCookie('sUniqueID');
       }

       $notes = Shopware()->container()->get('db')->fetchAssoc(
           'SELECT n.ordernumber as arrayKey, n.*
           FROM s_order_notes n, s_articles a
           WHERE (sUniqueID = ? OR (userID != 0 AND userID = ?))
           AND a.id = n.articleID AND a.active = 1 AND a.id = ?',
           [
               empty($uniqueId) ? Shopware()->container()->get('session')->get('sessionId') : $uniqueId,
               Shopware()->container()->get('session')->get('sUserId', 0),
               $productId
           ]
       );

       if (empty($notes)) {
           return false;
       } else {
           return true;
       }
   }
}

The controller’s template will display a button if the controller did indeed find the product on the user’s note list.

{if $onNote == true}
   {s name="DetailLinkNotepad" assign="snippetDetailLinkNotepad"}{/s}
   <button class="action--link link--notepad js--is-saved">
       <i class="icon--check"></i> 
       <span class="action--text">
           {s name="DetailNotepadMarked" namespace="frontend/detail/actions"}{/s}
       </span>
   </button>
{/if}

Now, when the user adds a product to his or her note list, it will be displayed on that user’s detail page for this product.