Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Консольные команды и 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 и получают ошибки. В консоли нет запроса, покупателя, корзины и сотрудника — контекст заполнен лишь частично. Команда должна получать всё нужное аргументами и работать через службы и запросы к базе, а не через контекст.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.