Представим ситуацию, что вы разрабатываете собственный модуль Custom, который выводит товары, срок годности которых скоро истекает. Ваш фронт-контроллер с помощью модели успешно сформировал выборку объектов Catalog::Model::Orm::Product и в шаблоне вам необходимо вывести количество дней, оставшихся до истечения каждого продукта. Наиболее наглядно в шаблоне выглядел бы вызов метода {$product->getRemainingDays()}, для получения количества оставшихся дней до истечения срока годности. Однако, метода getRemainingDays нет у объекта из модуля Catalog. Что делать?
Для решения данной проблемы создан механизм расширения поведения. Данный механизм позволяет расширять собственными методами "чужие" классы, поддерживающие интерфейс RS::Behavior::AcceptBehaviorInterface. Подключенный метод можно вызывать как обычный метод объекта.
"Расширение" извне поддерживают классы потомки RS::Behavior::AcceptBehavior, имплементирующие интерфейс RS::Behavior::AcceptBehaviorInterface. Интерфейс описывает следующие методы:
"Расширение" классов реализовано в методе __call, который перехватывает вызовы несуществующих функций. В теле функции __call происходит поиск запрошенного метода в подключенных "библиотеках" и если запрошенный метод обнаружен, то он вызывается, в противном случае выбрасывается исключение RS::Behavior::Exception.
В настоящее время интерфейс RS::Behavior::AcceptBehaviorInterface поддерживают все ORM объекты в системе, потомки RS::Orm::AbstractObject
Библиотекой методов (далее Библиотека) называется класс, потомок RS::Behavior::BehaviorAbstract, содержащий методы, которые будут подключены в последующем к другим классам.
В момент первого обращения к методу из библиотеки классов, создается отдельный экземпляр класса библиотеки, который привязан к расширяемому объекту, далее вызывается функция инициализация ModuleName::Model::Behavior::init, в которой происходит сохранение объекта расширяемого класса в свойство owner. Таким образом внутри библиотеки, обратиться к расширяемому объекту всегда можно с помощью $this->owner.
Рекомендуем размещать все классы "библиотеки" в пространстве имен не ниже .
Рассмотрим пример библиотеки методов.
Подключать библиотеки методов к сторонним классам рекомендуется в момент возникновения события initialize. Это самое первое событие за время выполнения скрипта, специально предназначенное для низкоуровневых инициализаций.
Подключение библиотеки методов ко всем объектам класса происходит с помощью вызова статического метода attachClassBehavior
Подключить библиотеку методов можно и к отдельному экземпляру класса на любом участе кода, например в контроллере, с помощью метода attachInstanceBehavior.
Другие примеры расширения поведения:
Подключение, отключение библиотек методов ко всем объектам
Подключение, отключение библиотек методов к одному объекту
Получение списка подключенных библиотек методов