Пишем класс для «Result»-события Joomla
Это продолжение статьи «Каждому событию Joomla — свой класс». В ней я расскажу как создать класс события, которое должно возвращать какой-либо результат.
Для чего мне потребовалось такое событие?
Для рассчёта стоимости и оформления доставки в Сдэк надо рассчитать размеры и вес посылок. На разных сайтах этот рассчёт происходит по разному: это может быть одна коробка для всех товаров в заказе, или каждый товар в своей коробке, или, например, стулья, которые штабелируются по нескольку штук в одну коробку.
Я решил вынести рассчёт размеров посылкомест в отдельные плагины и на каждом сайте использовать нужный плагин.
Теперь разберёмся как создать класс для этого события в Joomla 4. Забегая наперёд, скажу что нам в этом помогут интерфейс и трейты.
Имя события: onRadicalMartCdekCalculatorGetPackages
.
Класс события: GetPackagesEvent
.
Родительский класс: Joomla\CMS\Event\AbstractEvent
.
Интейфейс
Joomla\CMS\Event\Result\ResultAwareInterface
Используется для событий, обработчики которых должны возвращать что-то при вызове, аналогично тому, как работали многие события плагинов в более ранних версиях Joomla.
Этот интерфейс частично реализован трейтом ResultAware
. Метод typeCheckResult
реализован различными трейтами ResultTypeAware
. Ваше событие должно использовать как трейт ResultAware
, так и один из трейтов ResultTypeAware
. Например, если событие возвращает объекты, вам необходимо использовать трейты ResultAware
и ResultTypeObjectAware
в вашем классе.
Joomla предлагает следующие готовые «ResultTypeAware» трейты:
ResultTypeArrayAware
;ResultTypeBooleanAware
;ResultTypeFloatAware
;ResultTypeIntegerAware
;ResultTypeMixedAware
;ResultTypeNumericAware
;ResultTypeObjectAware
;ResultTypeStringAware
.
Трейты реализуют простую проверку добавляемых результатов функциями is_array
, is_boolean
и др. как можно догадаться из их названий.
Немного отличаются только ResultTypeMixedAware
, который ничего не проверяет и ResultTypeObjectAware
, который мы далее рассмотрим подробнее.
Трейты
Joomla\CMS\Event\Result\ResultAware
Свойства:
Запрещает установку аргумента результата напрямую с помощью setArgument('result', $value)
вместо использования addResult($value)
.
Методы:
Добавляет данные в массив результатов события.
Сеттер аргумента 'result'
, при установленном в true
свойстве класса события $preventSetArgumentResult
, бросает исключение.
Таким образом трейт ResultAware
не позволяет перезаписать результаты работы других плагинов. Плагины могут только добавлять свои результаты в массив.
Joomla\CMS\Event\Result\ResultTypeObjectAware
Этот трейт реализует ResultAwareInterface::typeCheckResult($data)
для проверки типа добавлемого результата.
События, использующие этот трейт (и трейт ResultAware)
, будут ожидать, что обработчики событий установят результаты соответствующего класса.
Если вы не зададите список допустимых классов результатов, любой объект PHP будет соответствовать этой проверке типа.
Свойства:
Могут ли значения атрибутов результата также быть NULL?
Допустимые имена классов для значений результатов.
Методы:
Проверяет тип данных, добавляемых к аргументу результата и бросает исключение в случае несоответствия.
Вот такой у меня получился класс события:
* @license GNU General Public License version 2 or later;
*/
namespace Joomla\Component\Radicalmartcdek\Administrator\Event\Service\CalculatorDelegate;
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Event\Result\ResultAware;
use Joomla\CMS\Event\Result\ResultAwareInterface;
use Joomla\CMS\Event\Result\ResultTypeObjectAware;
use Joomla\Component\Cdek\Site\Interface\CalculatorDelegateInterface;
use CdekSDK2\Model\Request\Calculator\TariffListPost\PackageRequest;
use function defined;
// phpcs:disable PSR1.Files.SideEffects
defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* @since 1.0.0
*/
class GetPackagesEvent extends AbstractEvent implements ResultAwareInterface
{
use ResultAware;
use ResultTypeObjectAware;
/**
* @param string $eventName Event name
* @param array $arguments Arguments
*
* @since 1.0.0
*/
public function __construct(string $eventName, array $arguments)
{
parent::__construct($eventName, $arguments);
$this->preventSetArgumentResult = true; // запрещаем прямую установку агрумента 'result'
$this->resultAcceptableClasses = [PackageRequest::class]; // класс для работы с посылкоместами Сдэка
}
/**
* @param CalculatorDelegateInterface $value Subject
*
* @return CalculatorDelegateInterface
*
* @since version
*/
protected function onSetSubject(CalculatorDelegateInterface $value): CalculatorDelegateInterface
{
return $value;
}
/**
* @param CalculatorDelegateInterface $value Subject
*
* @return CalculatorDelegateInterface
*
* @since version
*/
protected function onGetSubject(CalculatorDelegateInterface $value): CalculatorDelegateInterface
{
return $value;
}
/**
* @return CalculatorDelegateInterface
*
* @since 1.0.0
*/
public function getSubject(): CalculatorDelegateInterface
{
return $this->getArgument('subject');
}
/**
* @return PackageRequest[]
*
* @since 1.0.0
*/
public function getResult(): array
{
return $this->arguments['result'];
}
}