Консольные команды и cron
Часть работы не связана с открытием страницы: очистить старые записи, выгрузить заказы, пересчитать статистику. Такую работу оформляют консольной командой и запускают по расписанию. Команды PrestaShop — обычные команды Symfony, и модуль может добавить свои в общий список bin/console.
Встроенные команды
php bin/console list prestashop| Команда | Что делает |
|---|---|
prestashop:module install имя | Действия с модулем: install, uninstall, reset, enable, disable, upgrade |
cache:clear | Очищает кеш Symfony |
debug:router | Список маршрутов панели |
debug:container | Список служб |
prestashop:theme:enable имя | Включает тему |
Где лежит команда
Команды модуля хранят в src/Command. Нужна автозагрузка Composer из урока о службах. Создайте файл вручную:
modules/acmehello/
├── config/
│ └── services.yml
└── src/
├── Command/
│ └── CleanReviewsCommand.php
└── Repository/
└── ReviewRepository.phpКласс команды
<?php
// modules/acmehello/src/Command/CleanReviewsCommand.php
namespace Acme\Hello\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CleanReviewsCommand extends Command
{
protected function configure(): void
{
$this->setName('acmehello:reviews:clean');
$this->setDescription('Удаляет отзывы о товарах, которых больше нет.');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Команда работает.');
return 0;
}
}configure() задаёт имя и описание команды, execute() выполняет работу. Метод возвращает код завершения: 0 — успех, любое другое число — ошибка.
Регистрация
Команду объявляют службой с меткой console.command:
# modules/acmehello/config/services.yml
services:
acme.hello.command.clean_reviews:
class: Acme\Hello\Command\CleanReviewsCommand
tags:
- { name: console.command }Очистите кеш и запустите:
php bin/console cache:clear
php bin/console acmehello:reviews:cleanКонсоль напечатает «Команда работает.». Команда доступна, пока модуль установлен и включён.
Работа с данными
Добавьте в репозиторий метод, удаляющий отзывы о несуществующих товарах:
// modules/acmehello/src/Repository/ReviewRepository.php
public function deleteOrphans(): int
{
return (int) $this->connection->executeStatement(
'DELETE r FROM ' . $this->prefix . 'acmehello_review r
LEFT JOIN ' . $this->prefix . 'product p ON p.id_product = r.id_product
WHERE p.id_product IS NULL'
);
}Метод возвращает число удалённых строк. Репозиторий передают в команду через конструктор:
// modules/acmehello/src/Command/CleanReviewsCommand.php
private ReviewRepository $repository;
public function __construct(ReviewRepository $repository)
{
parent::__construct();
$this->repository = $repository;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$deleted = $this->repository->deleteOrphans();
$output->writeln('Удалено отзывов: ' . $deleted);
return 0;
}В начало файла добавьте use Acme\Hello\Repository\ReviewRepository;, а в описание службы — аргумент:
arguments:
- '@acme.hello.review_repository'Теперь команда печатает «Удалено отзывов: 0» или другое число.
Запуск по расписанию
Расписанием управляет не PrestaShop, а планировщик сервера — cron. Строку добавляют командой crontab -e:
0 3 * * * php /var/www/shop/bin/console acmehello:reviews:clean >> /var/www/shop/var/logs/acmehello-cron.log 2>&1Пять полей в начале — минута, час, день месяца, месяц и день недели. Эта строка запускает команду каждый день в 3:00 и дописывает её вывод в файл журнала.
Если консоли нет
На простом хостинге доступа к cron с командами может не быть, зато есть запуск адреса по расписанию. Тогда задачу оформляют контроллером витрины, который выполняет работу и проверяет секретный параметр:
// modules/acmehello/controllers/front/cron.php
if (!hash_equals((string) Configuration::get('ACMEHELLO_CRON_TOKEN'), (string) Tools::getValue('token'))) {
die('Forbidden');
}Секрет создают при установке модуля и показывают готовый адрес на странице настроек.
Частая ошибка
В команде обращаются к Context::getContext()->customer, cart или link и получают ошибки. В консоли нет запроса, покупателя, корзины и сотрудника — контекст заполнен лишь частично. Команда должна получать всё нужное аргументами и работать через службы и запросы к базе, а не через контекст.