Overrides
Hooks are not always enough: sometimes the behaviour of a core class itself has to change — the price calculation, for example. The legacy core has overrides for that: your class takes the place of a core class and replaces its methods. The mechanism is powerful but fragile, so it matters to know both how it works and why it is avoided.
How it works
Legacy core classes are declared with the Core ending: ProductCore, CartCore. The Product class used by all code is an empty child of ProductCore. That is the class you can replace with your own by putting a file into the override folder:
shop/
├── classes/
│ └── Product.php class ProductCore
└── override/
└── classes/
└── Product.php class Product extends ProductCoreAn override in a module
A module puts the file into its own override folder, repeating the path of the core class:
modules/acmehello/
├── acmehello.php
└── override/
└── classes/
└── Product.php<?php
// modules/acmehello/override/classes/Product.php
class Product extends ProductCore
{
public function getPrice($tax = true, $id_product_attribute = null, $decimals = 6, ...$rest)
{
$price = parent::getPrice($tax, $id_product_attribute, $decimals, ...$rest);
return (int) $this->id_category_default === 12 ? $price * 0.9 : $price;
}
}The method calls the parent calculation and lowers the price by ten percent for products of category 12.
Installation
When a module is installed, the engine moves the methods from its override folder into the shop's common override folder; on uninstall it removes them. So after adding the file the module is reset:
php bin/console prestashop:module reset acmehelloOpen the file override/classes/Product.php in the shop root: it now has the getPrice() method with a comment saying which module it came from.
What can be overridden
| What | Where it lives in the module |
|---|---|
| A core class | override/classes/Product.php |
| A front controller | override/controllers/front/ProductController.php |
| A back office controller | override/controllers/admin/AdminOrdersController.php |
Classes of the new core from the src folder cannot be replaced this way: hooks and Symfony services are used for them.
Why it is a last resort
| Problem | What it means |
|---|---|
| Conflict | Two modules cannot override the same method: the second one will not install |
| Upgrades | The signature of a core method changed — the shop is down |
| Debugging | Behaviour changes in a non-obvious place |
| Marketplace | Modules with overrides are accepted reluctantly |
An override affects the whole shop and all modules at once, so a bug in it breaks pages that have nothing to do with your module.
What to use instead
| Task | Instead of an override |
|---|---|
| Change a price | Catalog price rules or a SpecificPrice object |
| Add data to a page | A display hook |
| React to an object being saved | The actionObject...AddAfter, UpdateAfter hooks |
| Change a back office grid or form | The grid and form hooks from the previous lesson |
| Change the behaviour of a Symfony service | Service decoration in services.yml |
Look for a hook first. An override is for when there really is no hook and the task still has to be solved.
Troubleshooting
In debug mode the "Advanced Parameters → Performance" page has a "Disable all overrides" switch. If the shop behaves strangely, turn it on: when the behaviour is fixed, one of the overrides in the override folder is to blame.
Common mistake
An override file is added or changed, but the behaviour is the same. The engine keeps a class-to-file map in the cache. Delete the file var/cache/prod/class_index.php (in debug mode — var/cache/dev/class_index.php): it is recreated on the next request. The "Clear cache" button in the back office does the same.