Question

This question relates to optimization. I'm using 1.7.0.2 CE.

I am adding a CSS <body> class conditionally to my frontend page(s). I have used an XML rewrite to introduce my own logic:

File: app/code/local/Jongosi/Module/etc/config.xml
...
<global>
    <blocks>
        <page>
            <rewrite>
                <html>Jongosi_Module_Block_Page_Html</html>
            </rewrite>
        </page>
    </blocks>
</global>
...

In that class, I rewrite the getBodyClass method:

File: app/code/local/Jongosi/Module/Block/Page/Html.php

class Jongosi_Module_Block_Page_Html extends Mage_Page_Block_Html
{
    public function getBodyClass()
    {
        parent::getBodyClass();
        // my own logic here
        return $this;
    }
}

The 'problem' is that this method is called many times per page load (4 times on a default install on the home page, 8 times on product pages). My custom logic is fairly intensive.

The <body> class must be rewritten for every page load.

However, I don't want my logic to run 8 times because it is increasing the page load. I am currently using a cookie, set to 3 second lifetime, but it feels dirty. I set the cookie on first iteration and then read it for the remaining 7 loops.

I hope what I'm trying to do is clear. Is there a way to cache the result for the page load only, then have it re-run the logic on the next page load? I've trawled through the core, but nothing I've found seems to provide a good solution.

Thank you.

Was it helpful?

Solution

Your question isn't as context rich as I'd like, so my apologies if this answer is off base and not what you're looking for.

First, your method is returning $this, which is incorrect. If you look at the actual getBodyClass method

public function getBodyClass()
{
    return $this->_getData('body_class');
}

you'll see it's returning the contents of the body_class data property (which is set with setBodyClass, which is called by addBodyClass). So, you'll want to make sure your method actually returns a string that's a class name for the <body/> element.

For the remainder of this answer I'm going to assume you want to ignore Magento's logic to set a body class, and you're completely replacing that with your own.

Second, the caching you want can be achieved via straight PHP or with a Magento setter/getter. Consider your method

public function getBodyClass()
{
    $original_bodyclass = parent::getBodyClass();

    $my_custom_results = null;
    // my own logic here to populate $my_custom_results;

    return $my_custom_results;
}

Instead of writing it as the above, simply write it as

public function getBodyClass()
{
    $original_bodyclass = parent::getBodyClass();

    if(!$this->getMyCustomResults())
    {
        $my_custom_results = null;
        // my own logic here to populate $my_custom_results;
        $this->setMyCustomResults($my_custom_results);
    }
    return $this->getMyCustomResults();
}

The first time this is called your custom logic will run, and the value stored in a property.

The second time this is called the results that were stored the first time will be returned.

This is a pretty standard pattern used all over the Magento codebase. Using an object property works because Mage_Page_Block_Html is only instantiated once (i.e. it's always the same object). If you were dealing with multiple object instances but only wanted your code to run once, you'd store the cached results in a static property.

if(!self::$my_custom_results)
{
    //...populate local $my_custom_results
    self::$my_custom_results = $my_custom_results
}
return self::$my_custom_results;
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top