Новый функционал фреймворка - поведения (behavior)
В новой версии LS 2.0 появится функционал поведений (behaviors), который очень поход на подобный в Yii.
Суть сводится к тому, что теперь определенному типу объектов (пользователи, топики, блоги и т.п.) или конкретному объекту можно назначить через поведения определенный новый функционал.
Добавить новое поведение в объект достаточно просто, можно у объекта определить свойство
В этом примере добавляются два поведения — категории и дополнительные поля. В качестве ключа используется название поведение (далее по этому ключу можно обращаться к поведению), а в качестве значения идут параметры. Параметры идут произвольным массивом имя/значение,
Сами классы поведения привязаны к конкретному своему модулю и находятся в его подкаталоге behavior, здесь полная аналогия с Entity. На рисунке пример модуля с поведениям:
Название файла имеет вид
В самом простом варианте класс поведения может выглядеть так:
Поведения могут делать две вещи — добавлять новые методы в объект(есть исключение с Entity, об этом ниже) и вешать обработчики на хуки объекта.
Для добавления метода достаточно его описать в классе поведения и сделать у него видимость
Обработчики хуков добавляются через свойство $aHooks:
При объявлении хуков указывается их имя и коллбэк (обработчик в виде имени метода поведения), дополнительно можно указать приоритет.
Здесь есть важное отличие от стандартных хуков в ЛС — хуки в поведениях привязываются к конкретному объекту. Т.е. при срабатывании хука 'hook_one' в объекте топика, он будет обработан только тем поведением, которое привязано к этому конкретному топику. Из-за этой особенности такие хуки объявляются в коде чуть по другому, а именно:
Часто бывает, что наряду с хуком внутри объекта необходимо вызвать еще глобальный хук, то для этого достаточно передать третий параметр = true
Доступ к исходному объекту внутри поведения получается через
Если поведении принимает параметры и необходимо задать их дефолтные значения, то для этого достаточно просто в классе поведения объявить свойство $aParams.
Про исключение. В ЛС у сущностей Entity идет автоматическая обработка методов get*/set*/reload*, поэтому если поведение объявляет публичный метод, например, getMyData(), то напрямую к нему обратиться нельзя. Т.е. такой вызов
Сейчас в ЛС реализованы поведения для модуля дополнительных полей (Property) и на его основе они подключены к топику.
Суть сводится к тому, что теперь определенному типу объектов (пользователи, топики, блоги и т.п.) или конкретному объекту можно назначить через поведения определенный новый функционал.
Добавить новое поведение в объект достаточно просто, можно у объекта определить свойство
$aBehaviors
. Например:protected $aBehaviors=array( 'category'=>'ModuleCategory_BehaviorCategory', 'property'=>array( 'class'=>'ModuleProperty_BehaviorPropertyEntity', 'target_type'=>'article' ) );
В этом примере добавляются два поведения — категории и дополнительные поля. В качестве ключа используется название поведение (далее по этому ключу можно обращаться к поведению), а в качестве значения идут параметры. Параметры идут произвольным массивом имя/значение,
'class'
— это служебный параметр, означающий класс поведения. Если у повеления нет параметром, то его можно записать в короткой форме (смотри 'category'
). Альтернативным (скорее дополнительным) способом добавления поведения является прямой вызов метода AttachBehavior
, например:$oTopic->AttachBehavior('property','ModuleProperty_BehaviorPropertyEntity'); // далее можно убрать поведение $oTopic->DetachBehavior('property');
Сами классы поведения привязаны к конкретному своему модулю и находятся в его подкаталоге behavior, здесь полная аналогия с Entity. На рисунке пример модуля с поведениям:
Название файла имеет вид
[Name].behavior.class.php
, а сам класс Module[ModuleName]_Behavior[Name]
, который наследуется от класса Behavior.В самом простом варианте класс поведения может выглядеть так:
<?php class ModuleMain_BehaviorMy extends Behavior { public function NewMethod() { $sTwo=$this->getParam('two'); // .... } }
Поведения могут делать две вещи — добавлять новые методы в объект(есть исключение с Entity, об этом ниже) и вешать обработчики на хуки объекта.
Для добавления метода достаточно его описать в классе поведения и сделать у него видимость
'public'
, из примера выше это метод NewMethod()
. Теперь если объект топика объявил использование нашего поведения ( 'bar'=>'ModuleMain_BehaviorMy' ), то можно выполнить из топика метод поведения $oTopic->NewMethod();
, но лучше это делать через имя поведения — $oTopic->bar->NewMethod();
, в связи с тем, то у разных поведений могут совпадать имена методов. $this->getParam('two')
возвращает параметр с именем two, который был задан при объявлении поведения.Обработчики хуков добавляются через свойство $aHooks:
<?php class ModuleMain_BehaviorMy extends Behavior { protected $aHooks=array( 'hook_one'=>array( 'CallbackHookOne',1000 // приоритет ), 'hook_two'=>'CallbackHookTwo', ); public function CallbackHookOne($aParams) { // .... } public function CallbackHookTwo($aParams) { // .... } public function NewMethod() { // .... } }
При объявлении хуков указывается их имя и коллбэк (обработчик в виде имени метода поведения), дополнительно можно указать приоритет.
Здесь есть важное отличие от стандартных хуков в ЛС — хуки в поведениях привязываются к конкретному объекту. Т.е. при срабатывании хука 'hook_one' в объекте топика, он будет обработан только тем поведением, которое привязано к этому конкретному топику. Из-за этой особенности такие хуки объявляются в коде чуть по другому, а именно:
$this->RunBehaviorHook('hook_one'); $this->RunBehaviorHook('hook_two',array('param1'=>&$param1)); // вместо стандартного $this->Hook_Run('hook_one');
Часто бывает, что наряду с хуком внутри объекта необходимо вызвать еще глобальный хук, то для этого достаточно передать третий параметр = true
$this->RunBehaviorHook('hook_one',array(),true); // аналогичен двойному вызову $this->RunBehaviorHook('hook_one'); $this->Hook_Run('hook_one');
Доступ к исходному объекту внутри поведения получается через
$this->oObject
.Если поведении принимает параметры и необходимо задать их дефолтные значения, то для этого достаточно просто в классе поведения объявить свойство $aParams.
<?php class ModuleMain_BehaviorMy extends Behavior { protected $aParams=array( 'two'=>12345 ); public function NewMethod() { $iTopicId=$this->oObject->getId(); // .... } }
Про исключение. В ЛС у сущностей Entity идет автоматическая обработка методов get*/set*/reload*, поэтому если поведение объявляет публичный метод, например, getMyData(), то напрямую к нему обратиться нельзя. Т.е. такой вызов
$oTopic->getMyData()
не пройдет, для вызова метода нужно использовать имя поведения — $oTopic->my->getMyData()
. Такое ограничение есть только у Entity, у остальных объектов его нет. Но нужно понимать, что лучше всегда обращаться к методам через имя поведения, чтобы не было конфликтов с другими поведениями.Сейчас в ЛС реализованы поведения для модуля дополнительных полей (Property) и на его основе они подключены к топику.
17 комментариев
получает параметр-значение из расширенной записи
т.е. как в уии? Или из:
если из aParams, то что такое «target_type»:
если:
2. не совсем понятна работа хуков:
если мы прицепили хуки в поведения, а поведение к сущности топика, то вызов:
запустит выполнение хуков для каждой сущности топика?
это больше похоже на событийно-ориентированное программирование.3. «category» и «property» — это имя поведения? т.е:
то почему, тогда в примере указано имя «my» модуля поведения
?
2.
$this->RunBehaviorHook('hook_one');
запустит только один хук внутри конкретного объекта, где он был вызван, т.е. конкретного топика.3. да, имена. Имя может быть произвольным, поэтому в некоторых примерах 'my' (примеры независимы друг от друга)
берет параметр именно из aParams, в который попали из aBehaviors.
2.1. т.е. он зависим от контекста?
2.2. т.е. такой хук можно запускать только в сущности?
2.3. только в сущности, где было прицеплено поведение с этим хуком?
3. теперь понятно, но лучше об этом в топике написать либо примеры подправить чтобы уловить логику.
Сейчас такие хуки прописаны в ModuleORM и EntityORM
просто не могу тогда понять:
Еще раз — хук привязывается к тому объекту, от куда он был вызван через $this->RunBehaviorHook()