Переопределения
Хуков хватает не всегда: иногда нужно изменить само поведение класса ядра — например, расчёт цены. Для этого в старом ядре есть переопределение (override): свой класс встаёт на место класса ядра и подменяет его методы. Механизм мощный, но хрупкий, поэтому важно знать и как он работает, и почему его избегают.
Как это устроено
Классы старого ядра объявлены с окончанием Core: ProductCore, CartCore. Сам класс Product, которым пользуется весь код, — пустой наследник ProductCore. Именно его и можно заменить своим, положив файл в папку override:
shop/
├── classes/
│ └── Product.php class ProductCore
└── override/
└── classes/
└── Product.php class Product extends ProductCoreПереопределение в модуле
Модуль кладёт файл в свою папку override, повторяя путь к классу ядра:
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;
}
}Метод вызывает родительский расчёт и снижает цену на десять процентов для товаров категории 12.
Установка
При установке модуля движок переносит методы из его папки override в общую папку override магазина, при удалении — убирает их. Поэтому после добавления файла модуль сбрасывают:
php bin/console prestashop:module reset acmehelloОткройте файл override/classes/Product.php в корне магазина: в нём появился метод getPrice() с комментарием, из какого модуля он пришёл.
Что можно переопределить
| Что | Где лежит в модуле |
|---|---|
| Класс ядра | override/classes/Product.php |
| Контроллер витрины | override/controllers/front/ProductController.php |
| Контроллер панели | override/controllers/admin/AdminOrdersController.php |
Классы нового ядра из папки src так заменить нельзя: для них служат хуки и службы Symfony.
Почему это крайняя мера
| Проблема | В чём она |
|---|---|
| Конфликт | Два модуля не могут переопределить один метод: второй не установится |
| Обновления | Сигнатура метода ядра изменилась — магазин упал |
| Отладка | Поведение меняется в неочевидном месте |
| Маркетплейс | Модули с переопределениями принимают неохотно |
Переопределение действует на весь магазин и на все модули сразу, поэтому ошибка в нём ломает страницы, никак не связанные с вашим модулем.
Чем заменить
| Задача | Вместо переопределения |
|---|---|
| Изменить цену | Правила цен каталога или объект SpecificPrice |
| Добавить данные на страницу | Хук вывода |
| Реагировать на сохранение объекта | Хуки actionObject...AddAfter, UpdateAfter |
| Изменить таблицу или форму панели | Хуки таблиц и форм из прошлого урока |
| Изменить поведение службы Symfony | Декорирование службы в services.yml |
Сначала ищите хук. Переопределение — когда хука действительно нет, а задачу решить нужно.
Поиск неисправности
На странице «Расширенные параметры → Производительность» в режиме отладки есть переключатель «Отключить все переопределения». Если магазин ведёт себя странно, включите его: когда поведение исправилось, виновато одно из переопределений в папке override.
Частая ошибка
Файл переопределения добавили или изменили, а поведение прежнее. Движок хранит карту «класс — файл» в кеше. Удалите файл var/cache/prod/class_index.php (в режиме отладки — var/cache/dev/class_index.php): он создастся заново при следующем запросе. Кнопка «Очистить кеш» в панели делает то же.