Encodera

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

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

Оглавление

Службы Symfony в модуле

Пока весь код лежит в главном классе модуля, и он разрастается. Новое ядро PrestaShop построено на Symfony, и модуль может пользоваться его механизмом служб. Служба — обычный класс, объект которого создаёт контейнер: он сам передаёт в конструктор всё, что классу нужно, например подключение к базе.

Автозагрузка

Классы с пространством имён хранят в папке src. Чтобы PHP находил их без require_once, в корне модуля создают файл composer.json:

{
    "name": "acme/acmehello",
    "type": "prestashop-module",
    "autoload": {
        "psr-4": {
            "Acme\\Hello\\": "src/"
        }
    },
    "config": {
        "prepend-autoloader": false
    }
}

Запись psr-4 связывает пространство имён Acme\Hello с папкой src. Затем в папке модуля выполняют команду:

composer dump-autoload

Появится папка vendor с файлом autoload.php. Подключите его в начале главного файла модуля:

// modules/acmehello/acmehello.php
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once __DIR__ . '/vendor/autoload.php';
}

Структура

modules/acmehello/
├── acmehello.php
├── composer.json
├── config/
│   └── services.yml
├── src/
│   └── Repository/
│       └── ReviewRepository.php
├── vendor/
│   └── autoload.php
└── ...

Класс службы

Создайте вручную класс, который читает отзывы, — репозиторий:

<?php
// modules/acmehello/src/Repository/ReviewRepository.php
namespace Acme\Hello\Repository;
 
use Doctrine\DBAL\Connection;
 
class ReviewRepository
{
    private Connection $connection;
    private string $prefix;
 
    public function __construct(Connection $connection, string $prefix)
    {
        $this->connection = $connection;
        $this->prefix = $prefix;
    }
 
    public function countAll(): int
    {
        return (int) $this->connection->fetchOne(
            'SELECT COUNT(*) FROM ' . $this->prefix . 'acmehello_review'
        );
    }
}

Класс не обращается к Db::getInstance(): подключение к базе и приставку таблиц он получает через конструктор. Connection — подключение библиотеки Doctrine DBAL, которой пользуется новое ядро.

Регистрация службы

Службы модуля описывают в файле config/services.yml:

# modules/acmehello/config/services.yml
services:
  acme.hello.review_repository:
    class: Acme\Hello\Repository\ReviewRepository
    public: true
    arguments:
      - '@doctrine.dbal.default_connection'
      - '%database_prefix%'

Первая строка под services — имя службы. arguments перечисляет, что передать в конструктор: запись с @ — другая служба, запись в знаках % — параметр контейнера. public: true разрешает получать службу по имени.

Контейнер кешируется, поэтому после правки файла очистите кеш:

php bin/console cache:clear

Получение службы

В главном классе модуля службу получают методом get():

// modules/acmehello/acmehello.php, метод getContent
$total = $this->get('acme.hello.review_repository')->countAll();
 
$output .= $this->displayInformation(
    $this->trans('Всего отзывов: %count%', ['%count%' => $total], 'Modules.Acmehello.Admin')
);

Откройте страницу настроек модуля: над формой появится синяя плашка с числом отзывов.

Проверить, что служба зарегистрирована, можно из консоли:

php bin/console debug:container acme.hello.review_repository

Команда напечатает имя класса и аргументы службы.

Где действует файл

ФайлГде доступны службы
config/services.ymlВ панели управления и в консоли
config/admin/services.ymlТолько в панели
config/front/services.ymlТолько на витрине

На витрине контейнер меньше: служб панели в нём нет. Если служба нужна в хуке витрины, её описывают в config/front/services.yml и используют в аргументах только то, что там доступно.

Ещё один метод

// modules/acmehello/src/Repository/ReviewRepository.php
public function findLatest(int $limit = 5): array
{
    return $this->connection->fetchAllAssociative(
        'SELECT id_review, author, rating, date_add FROM ' . $this->prefix . 'acmehello_review
         ORDER BY date_add DESC LIMIT ' . (int) $limit
    );
}

Метод возвращает массив последних отзывов. Он понадобится на странице панели в следующем уроке.

Частая ошибка

Службу добавили в services.yml, а $this->get() отвечает, что такой службы нет. Обычно причин две: не очищен кеш контейнера или папка vendor не создана и класс не находится. Выполните composer dump-autoload в папке модуля и php bin/console cache:clear в корне магазина.

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

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