Jump to content

How cache an array of objects between pages


FluffyCat

Recommended Posts

Hi 

 

I have a small module that gets all the categories and puts them in an array like this:

$myCategories = Category::getHomeCategories($this->context->language->id);

 

However this is done in hookDisplayTop so every time a new page shows we have to ask the database for these categories. This just seems a bit unnecessary.

 

So I wonder if there is a way to cache, for the whole shop or for each user, this array with objects so that when I enter hookDisplayTop I could do something like:

 

if ($myCategories == NULL)

  $myCategories = Category::getHomeCategories($this->context->language->id);

 

Would this be more efficient than calling the function above for each page?

 

 

Link to comment
Share on other sites

You can do something like this :

$myCategories = Configuration::get('HOME_CAT_CACHE_'.$this->context->language->id);
if ($myCategories == '')
{
    $myCategories = json_encode(Category::getHomeCategories($this->context->language->id));
    Configuration::updateValue('HOME_CAT_CACHE_'.$this->context->language->id, $myCategories);
}
$myCategories = json_decode($myCategories);

At each page load there is MySQL request that load all Configuration values, so it will not add a request to use Configuration::get()

You should also add a condition to delete cache each day (that will help to refresh categories if they changed).

 

Edit : You could also cache the object in json in a cache file, but I think, in your case, store it in the Configuration::get will be okay :)

Edited by Fabien Serny (see edit history)
Link to comment
Share on other sites

Thanks for the answers. I am testing with the Cache approach now but it seems that it is clearing the cache between page loads right?

 

I have this code:

public function getCachedTopcats()
    {
        $cache_id = 'topcats_array' . $this->context->language->id;
        if (!Cache::isStored($cache_id))
        {
        echo "NOT CACHED";
        $topcats = Category::getHomeCategories($this->context->language->id);
            Cache::store($cache_id, $topcats);
        } else {
        echo "WAS CACHED";
        }
        return Cache::retrieve($cache_id);
    }
 
But reloading the page or moving to another page always prints the "NOT CACHED". So it seems this cache is invalidated between pageloads. Am I understanding that correctly? That the Cache class is only for caching things while on the same page or am I missing something here.
Link to comment
Share on other sites

Now I have tested Fabiens suggestion as well and it works fine, thanks a lot for the help.

 

Can I assume that this approach with storing the main categories in the Configuration should be faster than calling Category::getMainCategories for each pageload? Or am I trying to optimize something that does not really make a big difference?

 

Thanks again

Link to comment
Share on other sites

storing the array object in the configuration db table should be slightly more effective then executing the sql to locate the categories and building the array object.  but i assume we are talking milliseconds here.

 

storing the data in configuration database table will persist until you delete or change it, so now you need to deal with cleaning up the 'cache' whenever category data changes.

 

As for using the Cache object, it depends what the cache system is.  Using something like APC, then the objects will persist until they are pushed out or until the TTL expires.  This means the objects should survive multiple pageloads.  File system cache should also survive.  What cache system are you using?

 

The other mechanism is to use smarty cache.  If you are retrieving categories to be used within a smarty template, then just cache the smarty template file the first time and then re-use the cached template.  This way you only need to do the following one time (query the database, create the array object, create the template output).  Once that is done then you really only need to do it again when the underlying data or template changes.

Link to comment
Share on other sites

Now I have tested Fabiens suggestion as well and it works fine, thanks a lot for the help.

 

Can I assume that this approach with storing the main categories in the Configuration should be faster than calling Category::getMainCategories for each pageload? Or am I trying to optimize something that does not really make a big difference?

 

Thanks again

 

Yes, it will save you one DB request (that is not nothing when we're talking about product or categories :).

 

As I said, all Configuration values are load with one request at each page load. So adding one value, will not make the configuration load slower.

 

 

 

But reloading the page or moving to another page always prints the "NOT CACHED". So it seems this cache is invalidated between pageloads. Am I understanding that correctly? That the Cache class is only for caching things while on the same page or am I missing something here.

 

 

Cache class will use cache system configured in your back office.

If you're using CacheFS, for example, it might be a permission problem. If the directory "cache/cachefs/" is not writable, cache will only last during the page load since PS can't write cache file.

 

The other mechanism is to use smarty cache.  If you are retrieving categories to be used within a smarty template, then just cache the smarty template file the first time and then re-use the cached template.  This way you only need to do the following one time (query the database, create the array object, create the template output).  Once that is done then you really only need to do it again when the underlying data or template changes.

 

I totally agree with bellini13, Smarty cache will be better. I did not mention it since you talked about Smarty caching since you asked for array caching :)

Edited by Fabien Serny (see edit history)
Link to comment
Share on other sites

Thanks for all the help,

 

Actually, in the Prestashop backoffice the cache is not enabled but it is set to use APC from Plesk so it should be caching.

 

For the Smarty cache, is this something I must enable for my module? I thought it was on by default?

Link to comment
Share on other sites

Actually, in the Prestashop backoffice the cache is not enabled but it is set to use APC from Plesk so it should be caching.

 

If cache is not enabled in the back office, then using the Cache object would have no effect.  You have to enable cache, and then if you select APC, you need to ensure that APC is installed and configured on your server. 

 

For the Smarty cache, is this something I must enable for my module? I thought it was on by default?

Your module needs to properly use smarty templates, and more importantly needs to apply correct usage of template caching (ie.  when data changes you need to clear that cached template file so it can be re-created and cached again)

  • Like 1
Link to comment
Share on other sites

<< still prefers serialize :)

 

the one thing you will need to do, no matter how you approach this is to add hooks where possible that tell you to rebuild your file cache, for example if you are caching category tree, and new/changed/deleted  category, then have hook to take appropriate action.

Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...