Caching your views to improve the performance of your PrestaShop Modules

In this post I will talk about a very important topic in the development of PrestaShop modules: how to cache your template files to improve the performance of the modules. The relevance of this topic is even greater when we talk about Front-Office modules, because a bad written module may have serious impact in the loading time of the shop. The good news is that is very easy to use the PrestaShop own caching system.

As you may already know, all the HTML of the shop is (or should be) generated through some template language (usually smarty). As they are template languages, they must be compiled for the HTML to be generated. If no cache is used, every time a page is accessed, several template files have to be compiled, even if they didn’t change since the last compilation. This is a waste of server resources, and also makes the page to take more time to be load than it would be necessary. Thins get even worse if several database queries are performed to get the data used in the template.

As has already been said, the caching system of PrestaShop is very easy to be used, and you just have to include a few lines of code to your module. Let’s suppose that your module insert some content in the  Front-Office through the displayShoppingCartFooter hook. So, your code will be something like

When this function is executed, if there is a cached version of the template ‘mytemplate.tpl’, PrestaShop will automatically use the cached version, instead of recompile it. If your template didn’t depends of the $data variable, we wouldn’t need do to nothing more. However, as the value of the shopping cart changes, the HTML generated by this template may change as well. This makes necessary the use of some way to distinguish between different cached versions of the same template file.

These different versions may be produced using the third argument of the method Module::display(), named $cache_id, as the following code:

Now, we have different cached versions of the template file, and each version is indexed by the shopping cart value. It is a good practice to use the method Module::getCacheId(), which returns a string with the following information:

  • Whether the shop was accessed using secure connection or not;
  • ID of the shop (if using multishop);
  • ID of client group which the user who accessed the shop belongs to;
  • Language in use by the client;
  • Currency in use by the client;
  • Country in use by the client.

Then, a very good cache_id may be obtained like the following code.

Note that the variable $data is not used when the template is already in cache, because the template will not be compiled. So, if the template is in cache, the method MyModel::getSomeDbData() shouldn’t be called. Then, we can save some CPU resources with the following code.

Finally, the cache invalidation may be done with the method Module::_clearCache(). If we want to clear every cached version of our template file whenever any object of the class MyModel is updated, we may use the hook actionObjectMyModelUpdateAfter. This hook is called by PrestaShop whenever the method update() is executed with success in a object of the class MyModel (which must extends the PrestaShop class ObjectModel).

The method Module::_clearCache() also accepts the argument $cache_id, allowing us to clear the cache of a single version of our template file.

Developing a simple module with CRUD for PrestaShop

In this article, we will develop a module to be used in the administrative panel of the shop. This module implements the four basic CRUD operations, taking advantage of a lot of features that is already present in the PrestaShop’s core. Our forms and grids will all be generated automatically by the PrestaShop, in such a way that they will have the same layout as the pages of the shop. Also, it should make the module compatible with newer versions of the PrestaShop.

The following topics will be detailed:

  1. Automatic creation of database tables;
  2. Automatic reparation of the database in the module reinstallation;
  3. Listing data in a grid using only PrestaShop core features;
  4. Creating forms to create/update data using only PrestaShop core features;
  5. Deleting data from the database using individual and bulk actions.
  6. Utilization of multilanguage fields.

The items 1 and 2 will use the CustomObjectModel class. I developed this class to add some features to the PrestaShop’s ObjectModel class. So, our Model (we will have only one) must be defined in the same way that the PrestaShop’s ones are defined. I will show how to to this definition in this article. Once the model is defined, the 3., 4. and 5. items will demand little effort; the hard work is already implemented in the core of PrestaShop.

The full source of the module is available in this GitHub repository. You just have to extract it to /modules/crud folder. I strongly recommend that you read this article using the module in your own PrestaShop instance.

Module Configuration

In the begin of crud.php, we have the line

The models property must contain the name of every model that your module uses. This is not a PrestaShop requirement, but it is necessary to automatically create and repair the database. After that, we define the tabs that will be created in the backend menu.

With this definition, a tab name complete CRUD will be created in the backend menu, and will have the CRUD Model and Custom Operation children. The tabs are created using the addTab() method in the following code.

In line 17, we set the tab name for each language used in the shop. In line 25, we use the same addTab() function to create the children tabs. To remove the tabs, we use the following method.

With this basic methods, we may declare the model’s constructor, and install it.

The code above is self-explained, so we may continue to the install() method.

Firstly, we create the table associated to our model, if they didn’t exist yet. If they exist, but had some missing column, we create these missing columns in order to repair the database of the module. This is useful to fix errors that may occur after the upgrade to newer versions of the module.

Now, the following code displays the uninstall() method.

I really avoid to remove any database information when my modules are uninstalled, to avoid the losing of sensitive information. You may, instead, create a clean database method in the configuration page of your module, with the appropriated warning messages.

Model Creation

The model’s code is not that hard. We only need to detail the database configurations associated to the model (table name, column names/types, and so on). The following code may be found in the classes/CrudModel.php file.

The primary parameter is a column that will be assumed by the PrestaShop that is unique for each row in the database. Usually it will be the primary key of the table. The TYPE_INT, TYPE_STRING , TYPE_BOOL and TYPE_DATE constants are declared in the ObjectModel classvalidate refers to the name of some method of the Validation class, and will be automatically used to validate your model data before saving it in the database. Lastly, the db_type parameter required by CustomObjectModel for the database creation.

Controller Creation

As in the model, we does not have much work to do in the controller. Basically, we have to set the fields that will be displayed in our grid and the inputs that will be displayed in our create/update form. With this setup, PrestaShop will generate the grid and the forms automatically.

The controller must be placed in controllers/admin/AdminCrudModels.php. All the setup we need to do is made inside the class constructor, so we begin with the controller’s basic definition.

In line 7, we tell the controller to include the bootstrap files in the html of the page. The other parameters refers to our model table, primary key and class name. Now, we have to set the fields to be displayed in the list page.

The reader is invited to read the documentation of the HelperList class for more details of the code above. With line 14, the user will be able to change the status of our model by just clicking in the “v” or “x” icons. Also, the grid also gains the “Enable selected” and “Disable selected” bulk actions.

For the “Delete selected” bulk action, we need to insert the following code.

And to finish our list, let’s include some individual action buttons, as the following image.

This is easily achieved with the following code.

When the user clicks in the Edit button, he will see the following form, which will be automatically filled by PrestaShop.

He may also insert new register in the database, clicking in the “Insert new” button in the toolbar of the list.

(sorry, my shop is in pt-br)

To generate this form, we only have to add the following code to the controller’s constructor.

Again the reader is invited to check the documentation of the HelperForm class to understand the code above.

And this is everything we have to do to create a simple CRUD in the backend with PrestaShop. If you does not want so much customizations, this is really an easy task. However, if you wanna customize several elements of the page, you have to deeply check and understand what is behind the scenes. To do so, check the AdminControllerHelperList and HelperForm classes. They have almost all the code that is used to generate the pages that use used in this tutorial.

Using Multilanguage Fields

Multilanguage fields are fields that may have a different value for each language enabled in your shop. This is achieved with a table named <your_model_table>_lang, that contain a field named id_lang, a field named <your_model_primary_key> and any multi lang field of the model. This column and its fields will be created automatically by the CustomObjectModel class.

To configure a field as multilanguage in your model, you only have to modify the $definition property.

So, when you (re)install your module, the multilanguage table will be created automatically.

After the database is correctly created, we have to configure our controller in such a way that PrestaShop will allow us to easily create multilanguage records. This is achieved through the the $fields_form property of your controller.

Then, the form automatically created by PrestaShop will be like the following image.

Multi language fields created by the HelperForm class.

In the list action of your controller, PrestaShop will automatically display the value in the language that is configured by your user. With these two simple modifications, aided by the CustomObjectModel class, you have a fully functional multilanguage CRUD!

[PrestaShop] – Sending AJAX Requests to Admin Controllers

In this article I will talk about a problem that I had when developing my first PrestaShop module: how to do a AJAX request to my AdminControllers? Usually AJAX requests are not so difficult to be done, but things become more complicatet  when the target is a controller of the AdminController class.

Firstly, for the AJAX request to be done, there must have a record in the tab table related to the controller being targeted. You can create this tab whith the following code.

At line 3, if you set the tab as active, it will be displayed in the administration menu of the shop. If you are creating this controller just to send AJAX requests to it, leave active as 0. At line 9, tabname is the text that will be displayed in the administration menu, for each language that is installed in the shop. If you set active=0, this value is not important.

Now, your controller is already acessible through the url /adminpanel/index.php?controller=<controllername>. But all admin URLS must contain a security token for the request to reach the desired controller. For this token to be visible via Javascript, I usually set it as an attribute of some div in my template.

The controller responsible for generate the above template must set the $token$ variable with the security token.

Finally, we may do the AJAX request with the following code.

The code above will do a POST request to the method  ajaxProcess<ActionName> of the controller <controllername>.php. Notice that the method name is case sensitive. In the end, write this method in your controller.