Новые возможности по переопределению/наследованию классов LiveStreet

В LS появилась новая возможность для разработчиков плагинов — наследование классов. Идея была высказана еще avadim'ом здесь.
Эта возможность позволит удобно переопределять различные методы одного класса (модуля, экшена, сущности, маппера) разными плагинами без конфликтов.
Главное отличие от делегирование — не происходит блокировки переопределения класса для других плагинов. Также есть возможность переопределения одного метода разными плагинами, но здесь разработчикам нужно быть очень осторожными и делать так, чтоб свести вероятность конфликта к минимуму.

Как использовать.
Например, нужно переопределить метод получения пути до аватара у сущности пользователя в плагине 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 комментариев

avatar
котрые*
PluginTest_ModuleSide_EntityUser*
поправьте)

А в каком файле происходит переопределение? Просто интересно как работает)
avatar
а, вот, уже глянул через свн, спасибо)
avatar
охохох, только хотел остановиться на 0.4 и забить на последующие обновления… а тут )
Спасибо за функционал!
avatar
Ребята, а что делать с размерами аватаров, которые вы очень по-хакерски жестко в коде прописали?
avatar
avatar
Йоу.
avatar
Шэкарно пашет, спасибо.
avatar
Вывод раньше старта сессии.
avatar
Не пашет наследование.
avatar
Работает, но немного не так, как, например, я этого ожидал
avatar
Ох, ну и намучался… Из-за кривой кодировки плагин.хмл получал вывод до старта сессии.
avatar
Маленькая деталь, которая может привести к большим неприятностям: в предложенной мной схеме именование дочерних классов предлагалось таким:
class PluginName_Inherits_Parent {}

В том варианте, который сейчас реализован в движке, это сделано так:
class PluginName_Inherit_Parent {}

Т.е. пропущена буква «s» в конце слова _Inherits_. Поэтому могут возникнуть проблемы у тех, кто использовал наследование для своих разработок, как я описывал здесь: livestreet.ru/blog/4370.html

И еще нюанс, я предлагал использовать только имя модуля при задании наследнования, т.е. так:
public $aInherits=array('module' => array('Text'));

Но в текущей реализации движка это нужно делать так:
public $aInherits=array('module' => array('ModuleText'));

На мой взгляд, следовало все же оставить предложенный мной синтаксис, чтоб не возникало проблем с совместимостью, но… что имеем, то имеем, поэтому я обращаю внимение на это тех, кто писал (или планирует писать) плагины, использующие наследование.
avatar
PluginName_Inherit_Parent т.к. единственное число логичнее.
public $aInherits=array('module' => array('ModuleText'));
т.к. используется единый стиль — в качестве родителя указывается класс, что так же более логично.
avatar
т.к. единственное число логичнее
Вообще-то это глагол, и я, когда предлагал, подразумевал Present Indefinite (настоящее неопределнное время) — «наследует». Я тоже не сразу пришел к этой форме, почитал англоязычные тексты, исходники, и решил что правильно — так.

public $aInherits=array('module' => array('ModuleText'));
Тут тоже возникает разночтение, т.к. в этом месте указывается класс, а вот здесь:
$sText = $this->Text_Parse($sText)
уже не класс, а имя модуля. Если строго придерживаться единого стиля, то должно быть так:
$sText = $this->ModuleText_Parse($sText)
avatar
Вообще-то это глагол
да, точно. Но «наследовать» тоже не плохо.
Единый стиль имелся ввиду для обозначения наследников.
avatar
Думаю разработчикам движка следует по крайней мере проанализировать доводы, которые привел Вадим и, пока обновлению движка не приобрело массовость, внести необходимые корективы или уже договориться между собой и прийти к окончательному мнению. Нам, как пользователям очень важна стабильность, а сейчас складывается такое впечатление, что 0.4.1 не был последним релизом в настоящем полугодии или году.
avatar
у меня впечатление, что ты пытаешься делать выводы, будучи вообще не в теме :)
это уже не первый подобный «вывод»
avatar
Я высказался как пльзователь, а не как разработчик, и я конечно не в теме… и более того, не делаю никаких выводов, меня лишь заботит будет ли очередное обновление, поскольку вижу в связи с топиком какие-то расхождение во взглядах. Извини, что высказал свою озабоченность ((
avatar
Господа, а я могу наследовать и переопределять внешние библиотеки?
/lib/external/LiveImage/Image.php — напрмиер функция resize тут мне не нравится как работает, хочу подхачить. Что делать?

Спасибо.
avatar
Уж если переопределять, то никак не внешнюю библиотеку, а модуль ModuleImage.
avatar
Модуль Image использует библиотеку LiveImage и, в частности, функцию resize библиотеки LiveImage.
avatar
Интерфес другой библиотеки может совсем не совпадать с интерфейсом LiveImage. Модуль как раз и нужен, чтобы стнадартизировать вызовы. Если требуется юзать другую библиотеку, то надо переопределить модуль и уже в новом модуле подключать ее.
avatar
В данном случае стандартная библиотека использует внешнюю, поэтому можно считать что внешняя является стандартной библиотекой. Да бог с ним, с данным случаем. Наследовать можно внешнюю библиотеку или нет — вопрос остается открытым :)
avatar
Вообще задача то всего лишь заменить в функции resize модуля LiveImage такое
$this->scale = min($scale_x, $scale_y);

на такое
$this->scale = max($scale_x, $scale_y);

— это все, что мне требуется )
avatar
Ну и вообще, причины могут быть, интересно в теории…
avatar
Помогите пожалуйста:
protected $aInherits=array(
'module' =>array('PluginAceMySearch_ModuleMySearch' => 'PluginMyVorks_ModuleMySearch')
РАБОТАЕТ а
'action' =>array ('PluginAceMySearch_ActionMySearch' => 'PluginMyVorks_ActionMySearch')
НЕ РАБОТАЕТ
Что делаю не так?, пробовал разные варианты именований все бестолку екшен плагина не переопределяется…
avatar
сейчас нельзя переопределить экшен плагина, исправим в след версиях
avatar
на самом деле работает, например
protected $aInherits=array(		
		'action'=>array('PluginPage_ActionPage'=>'_ActionTest'),
	);
переопределит экшен плагина, но для полного счастья необходимо в своем плагине создать все шаблоны переопределяемого плагина
avatar
это еще не исправлено?
avatar
и что делать, если нужно переопределить, например, лишь один метод из всего экшена?
avatar
для переопределения одного метода экшена плагина пока ничего не сделать
avatar
А мне вроде бы удалось, я переопределил ActionBlog::EventShutdown… Вроде бы правильно работает.
avatar
ActionBlog::EventShutdown
это стандартный экшен, а здесь имеется ввиду переопределение именно экшена плагина из другого плагина
avatar
а делегироваие получится использовать?
avatar
пофиксено в svn.
теперь можно спокойно наследовать плагины хоть 10 раз )
avatar
Привет,
объясните в чем глюк:
есть два плагина, которые наследуют один класс, скажем 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().
Или я все-таки чего то не понимаю?
avatar
не смог воспроизвести
версия движка 0.4.1?
вот тестовые плагины livestreet.ru/uploads/plugins_for_test.zip
avatar
Ух, блин, разобрался… Все правильно — работает. Не стер кэш… Все оттуда росло, запрашивало классы плагинов, которые отключены. Целый день коту под хвост…
avatar
Я тоже с кешем долго стучал в бубен. Решил на локалке его вообще отключить :)
avatar
Товарищи. кто может рассказать, что на текущий момент в транке поменялось относительно 0.4.1 в плане разработки
Очень лениво смотреть каждый коммит
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.