🎉 Proudly, we are happy to announce the only Headless solution for PrestaShop. Read More

Learn PrestaShop Symfony basics with an example - Conversion rate and Net Profit are infinite.

Learn PrestaShop Symfony basics with an example - Conversion rate and Net Profit are infinite.

If you do not know what are Symfony container, Symfony services and the dependency injection concepts, I recommend reading this tiny article to gain a tangible understanding of these concepts. You need to know more and read more, but it can be a good start. I try to give you this understanding with a simple example.

Scenario

After uninstalling analytical and statistical modules (because of performance issues) you may see that the Conversion rate and Net profit show an infinite value (or you may have noticed accidentally). That's because Conversion rate and Net profit KPIs get their data from those modules.

How to Fix?

To solve this issue we should either install those modules again, or remove the widgets from Order page in Back Office. First, you may try to find a tpl/twig file to remove these two simple widgets, but I'm going to show you a different way to do that (you may remove the HTML completely, or you may use KpiRowModifier hook.).

What I'm going to do?

In this tiny article, I'm going to to show you how to easily remove these widgets from Orders page in Back-office. Before going further we need to know a little more about new PrestaShop controllers and Symfony concepts if you are not familiar with them.

Symfony and New Controllers

Unlike the front-office, most of the back-office pages have been migrated to a new way of coding in the past years. I'm talking about Symfony and dependency injection, you probably knew that.

Most of the back-office pages are backed by modern controllers, which have Symfony support. When Symfony comes in, we expect to see dependency injection (DI) and an object pool/container, and also a way to inject (to bind to wire) those objects (services) in together in run-time, through a file (XML or Yaml) or through annotations (in most programming languages like java the feature of adding metadata to classes, fields or methods is called annotation. FYI and to research more, the process of reading these metadata information in run-time is done by reflection technology). As far as I know, Symfony 5.2 introduced Autowiring with Attributes (attributes introduced in PHP 8, a new way to annotate), however it already has supported annotations (Doctrine Annotations).

Nevertheless, in PrestaShop there are yaml files to put the wiring information to bind and connect objects (services). But why we need these info?

Because, PrestaShop back-office is changing more and more to support Symfony-style. So, if we want to modify the existing features and to develop new features we need to know about the concepts.
Oh! what about the widgets in BO Order page..

Okay! Let's remove those two KPIs!

Now, we know that most of the PrestaShop back office pages have Symfony components. Let's go to Orders BO controller and indextAction method and take a look at the first line:

public function indexAction(Request $request, OrderFilters $filters)
  {
    $orderKpiFactory = $this->get('prestashop.core.kpi_row.factory.orders');
    $orderGrid = $this->get('prestashop.core.grid.factory.order')->getGrid($filters);

    $changeOrderStatusesForm = $this->createForm(ChangeOrdersStatusType::class);
.
.

This line of code:

    $orderKpiFactory = $this->get('prestashop.core.kpi_row.factory.orders');

is responsible to build the top KPI elements (the four default widgets) of the Order page in back-office. Actually, we are requesting the container to give us an object with this line of code. $this->get is a reference to our container, and gets an argument which is a key to our registered service.

The container gets the key and returns back an instance of the requested object (creates an object from that concrete class). Simply, think of the container a pool of objects that holds the application's objects within it. You can read more about these concepts if you search for these keywords, dependency injection, object pooling, IoC container, inversion of control, factory design pattern, single tone and prototype objects. You also need to have a good understanding of interface usages, abstractions and specifications..

The container creates an instance of this concrete class src/Core/Kpi/Row/HookableKpiRowFactory.php and the returns back the object. Now, the class will handle the rest of the work for UI rendering. The class HookableKpiRowFactory has an instance variable named $kpis, this array keeps the UI elements that should be placed in KPI section (Do you remember that I mentioned that the proper way to remove KPIs is to use hooks? This arrays is the one that we should change it through KpiRowModifier hook). But how they are being populated?

The $kpis array comes from outside of the class. Again, here our container comes in and injects the array into our instance (this type of injection is called constructor based dependency injection, you can read more about other methods like setter-based and autowiring).

How the container detects which class should be injected?

The answer is the definition file. Take a look at the file located in this directory: src/PrestaShopBundle/Resources/config/services/core/kpi.yml. Within the file, the services related to the KPI are defined.

    prestashop.core.kpi_row.factory.orders:
        class: PrestaShop\PrestaShop\Core\Kpi\Row\HookableKpiRowFactory
        arguments:
          -
            - '@prestashop.adapter.kpi.conversion_rate'
            - '@prestashop.adapter.kpi.abandoned_cart'
            - '@prestashop.adapter.kpi.average_order_value'
            - '@prestashop.adapter.kpi.net_profit_per_visit'
          - '@prestashop.core.hook.dispatcher'
          - 'orders'

This way, the container detects which class and arguments should be injected. As you see, the arguments are the keys to KPI classes which are responsible to render their logic. For example, the class src/Adapter/Kpi/ConversionRateKpi.php is the concrete class responsible for conversion rate logic. Seems that we found it..

Let's remove the two KPIs

Go to the class: src/Adapter/Kpi/ConversionRateKpi.php and try to remove these two lines:

            - '@prestashop.adapter.kpi.conversion_rate'
            - '@prestashop.adapter.kpi.net_profit_per_visit'

Now, try to do a clear cache in your PrestaShop BO, to remove Symfony cache files. And finished! You should see just two KPIs in your Order page.

That was a quick overview of how Symfony container works with an example in PrestaShop context and to have a better understanding of these concepts. If you want to know more about Symfony services and how you can use them, you can check this article.

A better way to manipulate KPIs in Back-office Order page..

If we want to modify KPI elements in Order page, there is a better way to do that. We can also override KPI items with a hook named KpiRowModifier through a module. But in this article I use the first method just to explain Symfony concepts. (actually the new hookable class created to add the dynamicity to the KPI section in BO)

Take a look at other topics in this category: Modern PrestaShop and Symfony related topics

Posted 2 weeks ago by Sam Berry

Comments

Add a comment