Новые возможности по переопределению/наследованию классов LiveStreet
В LS появилась новая возможность для разработчиков плагинов — наследование классов. Идея была высказана еще avadim'ом здесь.
Эта возможность позволит удобно переопределять различные методы одного класса (модуля, экшена, сущности, маппера) разными плагинами без конфликтов.
Главное отличие от делегирование — не происходит блокировки переопределения класса для других плагинов. Также есть возможность переопределения одного метода разными плагинами, но здесь разработчикам нужно быть очень осторожными и делать так, чтоб свести вероятность конфликта к минимуму.
Здесь мы указали, что сущность пользователя ModuleUser_EntityUser будет переопределена сущностью-наследником PluginTest_ModuleSide_EntityUser модуля Side плагина Test. Также можно использовать короткий синтаксис объявления наследований (все варианты эквиваленты):
Создаем файл /plugins/test/classes/modules/side/entity/User.entity.class.php с таким содержанием:
Правило наименования родительского класса такое — сначала указываем плагин, затем ключевое слово Inherit и далее имя класса от которого происходит наследование. В итоге в нашем примере получаем PluginTest_Inherit_ModuleUser_EntityUser.
В результате везде вызовы getProfileAvatarPath() у сущности юзера будут переопределены плагином Test.
Другой пример. Пусть будет два плагина, которые переопределяют один и тотже метод Parser() модуля Text для дополнительной обработки текста.
Первый плагин:
Модуль первого плагина (/plugins/test/classes/modules/side/Side.class.php):
Второй плагин:
Модуль второго плагина (/plugins/test2/classes/modules/text/Text.class.php):
В итоге при создании топика с текстом "blabla" получим на выходе "[from plugin Test 2] blabla [from plugin Test]".
Просьба потестировать новый функционал, он работает начиная с версии LiveStreet 0.4.1.
P.S. Движок перестал поддерживать кастомные классы модулей и сущностей, т.к. этот функционал сполна перекрывается делегированием и наследованием.
Эта возможность позволит удобно переопределять различные методы одного класса (модуля, экшена, сущности, маппера) разными плагинами без конфликтов.
Главное отличие от делегирование — не происходит блокировки переопределения класса для других плагинов. Также есть возможность переопределения одного метода разными плагинами, но здесь разработчикам нужно быть очень осторожными и делать так, чтоб свести вероятность конфликта к минимуму.
Как использовать.
Например, нужно переопределить метод получения пути до аватара у сущности пользователя в плагине Test. В плагине необходимо объявить те классы, которые будут наследоваться. Объявление происходит в свойстве $aInherits:<?php
class PluginTest extends Plugin {
protected $aInherits=array(
'entity' =>array('ModuleUser_EntityUser'=>'_ModuleSide_EntityUser')
);
public function Activate() {
return true;
}
public function Init() {
}
}
?>
Здесь мы указали, что сущность пользователя ModuleUser_EntityUser будет переопределена сущностью-наследником PluginTest_ModuleSide_EntityUser модуля Side плагина Test. Также можно использовать короткий синтаксис объявления наследований (все варианты эквиваленты):
<?php
protected $aInherits=array(
'entity' =>array('ModuleUser_EntityUser')
);
protected $aInherits=array(
'entity' =>array('ModuleUser_EntityUser' => '_ModuleUser_EntityUser')
);
protected $aInherits=array(
'entity' =>array('ModuleUser_EntityUser' => 'PluginTest_ModuleUser_EntityUser')
);
?>
Создаем файл /plugins/test/classes/modules/side/entity/User.entity.class.php с таким содержанием:
<?php
class PluginTest_ModuleSide_EntityUser extends PluginTest_Inherit_ModuleUser_EntityUser {
public function getProfileAvatarPath($iSize) {
return 'путь до новой картинки аватара';
}
}
?>
Правило наименования родительского класса такое — сначала указываем плагин, затем ключевое слово Inherit и далее имя класса от которого происходит наследование. В итоге в нашем примере получаем PluginTest_Inherit_ModuleUser_EntityUser.
В результате везде вызовы getProfileAvatarPath() у сущности юзера будут переопределены плагином Test.
Другой пример. Пусть будет два плагина, которые переопределяют один и тотже метод Parser() модуля Text для дополнительной обработки текста.
Первый плагин:
<?php
class PluginTest extends Plugin {
protected $aInherits=array(
'module'=>array('ModuleText'=>'_ModuleSide'),
);
public function Activate() {
return true;
}
public function Init() {
}
}
?>
Модуль первого плагина (/plugins/test/classes/modules/side/Side.class.php):
<?php
class PluginTest_ModuleSide extends PluginTest_Inherit_ModuleText {
public function Parser($sText) {
$sResult=parent::Parser($sText);
// обрабатываем текст
sResult=$sResult.' [from plugin Test]';
return $sResult;
}
}
?>
Второй плагин:
<?php
class PluginTest2 extends Plugin {
protected $aInherits=array(
'module'=>array('ModuleText'),
);
public function Activate() {
return true;
}
public function Init() {
}
}
?>
Модуль второго плагина (/plugins/test2/classes/modules/text/Text.class.php):
<?php
class PluginTest2_ModuleText extends PluginTest2_Inherit_ModuleText {
public function Parser($sText) {
$sResult=parent::Parser($sText);
return '[from plugin Test 2] '.$sResult;
}
}
?>
В итоге при создании топика с текстом "blabla" получим на выходе "[from plugin Test 2] blabla [from plugin Test]".
Просьба потестировать новый функционал, он работает начиная с версии LiveStreet 0.4.1.
P.S. Движок перестал поддерживать кастомные классы модулей и сущностей, т.к. этот функционал сполна перекрывается делегированием и наследованием.
40 комментариев
PluginTest_ModuleSide_EntityUser*
поправьте)
А в каком файле происходит переопределение? Просто интересно как работает)
Спасибо за функционал!
В том варианте, который сейчас реализован в движке, это сделано так:
Т.е. пропущена буква «s» в конце слова _Inherits_. Поэтому могут возникнуть проблемы у тех, кто использовал наследование для своих разработок, как я описывал здесь:
И еще нюанс, я предлагал использовать только имя модуля при задании наследнования, т.е. так:
Но в текущей реализации движка это нужно делать так:
На мой взгляд, следовало все же оставить предложенный мной синтаксис, чтоб не возникало проблем с совместимостью, но… что имеем, то имеем, поэтому я обращаю внимение на это тех, кто писал (или планирует писать) плагины, использующие наследование.
т.к. используется единый стиль — в качестве родителя указывается класс, что так же более логично.
Тут тоже возникает разночтение, т.к. в этом месте указывается класс, а вот здесь:
уже не класс, а имя модуля. Если строго придерживаться единого стиля, то должно быть так:
Единый стиль имелся ввиду для обозначения наследников.
это уже не первый подобный «вывод»
/lib/external/LiveImage/Image.php — напрмиер функция resize тут мне не нравится как работает, хочу подхачить. Что делать?
Спасибо.
на такое
— это все, что мне требуется )
protected $aInherits=array(
'module' =>array('PluginAceMySearch_ModuleMySearch' => 'PluginMyVorks_ModuleMySearch')
РАБОТАЕТ а
'action' =>array ('PluginAceMySearch_ActionMySearch' => 'PluginMyVorks_ActionMySearch')
НЕ РАБОТАЕТ
Что делаю не так?, пробовал разные варианты именований все бестолку екшен плагина не переопределяется…
переопределит экшен плагина, но для полного счастья необходимо в своем плагине создать все шаблоны переопределяемого плагина
теперь можно спокойно наследовать плагины хоть 10 раз )
объясните в чем глюк:
есть два плагина, которые наследуют один класс, скажем UserEntity модуля User
В пeрвом плагине пишем в файле PluginOne.class.php
class PluginOne extends Plugin
{
protected $aInherits=array(
'entity' => array('ModuleUser_EntityUser'=> PluginOne_ModuleUser_EntityUser'));
…
}
во втором то же самое
class PluginTwo extends Plugin
{
protected $aInherits=array(
'entity' => array('ModuleUser_EntityUser'=> PluginTwo_ModuleUser_EntityUser'));
…
}
файлы плагинов называются plugins/one/classes/modules/user/entity/User.entity.class.php и plugins/two/classes/modules/user/entity/User.entity.class.php соответственно
сами классы определяются так:
class PluginOne_ModuleUser_EntityUser extends PluginOne_Inherit_ModuleUser_EntityUser {....}
и
class PluginTwo_ModuleUser_EntityUser extends PluginTwo_Inherit_ModuleUser_EntityUser {....}
В итоге получаю такую ошибку:
Fatal error: Class 'PluginOne_ModuleUser_EntityUser' not found in /../engine/include/function.php(414): eval()'d code on line 1
В месте ошибки выполняется код:
eval('abstract class '. $alias. ' extends '. $original. ' {}');
где $alias это то самое PluginOne_Inherit_ModuleUser_EntityUser, а $original член массива $aInherits.
В данный момент( исключения ) в массиве $aInherits[ModuleUser_EntityUser] два члена, добавляемых каждым из плагинов:
вот части касающиеся имен классов
[inherit] => PluginOne_ModuleUser_EntityUser
и
[inherit] => PluginTwo_ModuleUser_EntityUser
В результате выполнения функции GetParentInherit() модуля Plugin, которая возвращает верх стека наследования, в данном случае PluginOne_ModuleUser_EntityUser, получаем выполнение функцией eval такого кода:
abstract class PluginOne_Inherit_ModuleUser_EntityUser extends PluginOne_ModuleUser_EntityUser;
Собственно на этом и произошла ошибка. Ведь PluginOne_ModuleUser_EntityUser еще не определен.
Мне кажется, что это работало бы, если раскручивать стек с другой стороны, т.е должна быть такая последовательность
abstract class PluginOne_Inherit_ModuleUser_EntityUser extends ModuleUser_EntityUser;
abstract class PluginTwo_Inherit_ModuleUser_EntityUser extends PluginOne_ModuleUser_EntityUser;
Т.е. надо переделывать функцию GetParentInherit().
Или я все-таки чего то не понимаю?
версия движка 0.4.1?
вот тестовые плагины livestreet.ru/uploads/plugins_for_test.zip
Очень лениво смотреть каждый коммит