ModulePlugin
Package | engine.modules |
---|---|
Inheritance | class ModulePlugin » Module » LsObject |
Since | 1.0 |
Source Code | /engine/modules/plugin/Plugin.class.php |
Protected Properties
Property | Type | Description | Defined By |
---|---|---|---|
aDelegates | array | Список engine-rewrite`ов (модули, экшены, сущности, шаблоны) | ModulePlugin |
aInherits | array | Стек наследований | ModulePlugin |
aPluginsList | array | Список плагинов | ModulePlugin |
bIsInit | bool | Указывает на то, была ли проведенна инициализация модуля | Module |
oEngine | Engine | Объект ядра | Module |
sPluginsDir | string | Путь к директории с плагинами | ModulePlugin |
Public Methods
Method | Description | Defined By |
---|---|---|
Delegate() | Перенаправление вызовов на модули, экшены, сущности | ModulePlugin |
Delete() | Удаляет плагины с сервера | ModulePlugin |
GetActivePlugins() | Возвращает список активированных плагинов в системе | ModulePlugin |
GetDelegate() | Возвращает делегат модуля, экшена, сущности. | ModulePlugin |
GetDelegateObjectList() | Возвращает список объектов, доступных для делегирования | ModulePlugin |
GetDelegateSign() | Возвращает подпись делегата модуля, экшена, сущности. | ModulePlugin |
GetDelegater() | Возвращает делегирующий объект по имени делегата | ModulePlugin |
GetDelegates() | ModulePlugin | |
GetDelegationChain() | Возвращает цепочку делегатов | ModulePlugin |
GetInherits() | Возвращает список наследуемых классов | ModulePlugin |
GetLastInherit() | Возвращает последнего наследника в цепочке | ModulePlugin |
GetList() | Получает список информации о всех плагинах, загруженных в plugin-директорию | ModulePlugin |
GetParentInherit() | Получает следующего родителя у наследника. | ModulePlugin |
GetRootDelegater() | Возвращает делегируемый класс | ModulePlugin |
Inherit() | Добавляет в стек наследника класса | ModulePlugin |
Init() | Инициализация модуля | ModulePlugin |
SetActivePlugins() | Записывает список активных плагинов в файл PLUGINS.DAT | ModulePlugin |
SetInit() | Помечает модуль как инициализированный | Module |
Shutdown() | Метод срабатывает при завершении работы ядра | Module |
Toggle() | Переключает состояние плагина активный/не активный | ModulePlugin |
__call() | Ставим хук на вызов неизвестного метода и считаем что хотели вызвать метод какого либо модуля | Module |
__construct() | При создании модуля передаем объект ядра | Module |
collectAllDelegatesRecursive() | Составляет цепочку делегатов | ModulePlugin |
isDelegated() | Возвращает true, если устано | ModulePlugin |
isDelegater() | Возвращает true, если установлено правило делегирования | ModulePlugin |
isInit() | Возвращает значение флага инициализации модуля | Module |
Protected Methods
Method | Description | Defined By |
---|---|---|
Xlang() | Получает значение параметра из XML на основе языковой разметки | ModulePlugin |
__clone() | Блокируем копирование/клонирование объекта | Module |
Property Details
Список engine-rewrite`ов (модули, экшены, сущности, шаблоны) Определяет типы объектов, которые может переопределить/унаследовать плагин
Стек наследований
Список плагинов
Путь к директории с плагинами
Method Details
public void Delegate(string $sType, string $sFrom, string $sTo, string $sSign='ModulePlugin')
| ||
$sType | string | |
$sFrom | string | |
$sTo | string | |
$sSign | string |
public function Delegate($sType,$sFrom,$sTo,$sSign=__CLASS__) {
/**
* Запрещаем неподписанные делегаты
*/
if(!is_string($sSign) or !strlen($sSign)) return null;
if(!in_array($sType,array_keys($this->aDelegates)) or !$sFrom or !$sTo) return null;
$this->aDelegates[$sType][trim($sFrom)]=array(
'delegate'=>trim($sTo),
'sign'=>$sSign
);
}
Перенаправление вызовов на модули, экшены, сущности
public void Delete(array $aPlugins)
| ||
$aPlugins | array | Список плагинов для удаления |
public function Delete($aPlugins) {
if(!is_array($aPlugins)) $aPlugins=array($aPlugins);
$aActivePlugins=$this->GetActivePlugins();
foreach ($aPlugins as $sPluginCode) {
/**
* Если плагин активен, деактивируем его
*/
if(in_array($sPluginCode,$aActivePlugins)) $this->Toggle($sPluginCode,'deactivate');
/**
* Удаляем директорию с плагином
*/
func_rmdir($this->sPluginsDir.$sPluginCode);
}
}
Удаляет плагины с сервера
public array GetActivePlugins()
| ||
{return} | array |
public function GetActivePlugins() {
/**
* Читаем данные из файла PLUGINS.DAT
*/
$aPlugins=@file($this->sPluginsDir.Config::Get('sys.plugins.activation_file'));
$aPlugins =(is_array($aPlugins))?array_unique(array_map('trim',$aPlugins)):array();
return $aPlugins;
}
Возвращает список активированных плагинов в системе
public string GetDelegate(string $sType, string $sFrom)
| ||
$sType | string | |
$sFrom | string | |
{return} | string |
public function GetDelegate($sType,$sFrom) {
if (isset($this->aDelegates[$sType][$sFrom]['delegate'])) {
return $this->aDelegates[$sType][$sFrom]['delegate'];
} elseif ($aInherit=$this->GetLastInherit($sFrom)) {
return $aInherit['inherit'];
}
return $sFrom;
}
Возвращает делегат модуля, экшена, сущности. Если делегат не определен, пытается найти наследника, иначе отдает переданный в качестве sender`a параметр
public array GetDelegateObjectList()
| ||
{return} | array |
public function GetDelegateObjectList() {
return array_keys($this->aDelegates);
}
Возвращает список объектов, доступных для делегирования
public string|null GetDelegateSign(string $sType, string $sFrom)
| ||
$sType | string | |
$sFrom | string | |
{return} | string|null |
public function GetDelegateSign($sType,$sFrom) {
if (isset($this->aDelegates[$sType][$sFrom]['sign'])) {
return $this->aDelegates[$sType][$sFrom]['sign'];
}
if ($aInherit=$this->GetLastInherit($sFrom)) {
return $aInherit['sign'];
}
return null;
}
Возвращает подпись делегата модуля, экшена, сущности.
public string GetDelegater(string $sType, string $sTo)
| ||
$sType | string | Объект |
$sTo | string | Делегат |
{return} | string |
public function GetDelegater($sType,$sTo) {
$aDelegateMapper=array();
foreach($this->aDelegates[$sType] as $kk=>$vv) {
if ($vv['delegate']==$sTo) {
$aDelegateMapper[$kk]=$vv;
}
}
if (is_array($aDelegateMapper) and count($aDelegateMapper)) {
$aKeys=array_keys($aDelegateMapper);
return array_shift($aKeys);
}
foreach ($this->aInherits as $k=>$v) {
$aInheritMapper=array();
foreach($v['items'] as $kk=>$vv) {
if ($vv['inherit']==$sTo) {
$aInheritMapper[$kk]=$vv;
}
}
if (is_array($aInheritMapper) and count($aInheritMapper)) {
return $k;
}
}
return $sTo;
}
Возвращает делегирующий объект по имени делегата
public array|null GetDelegates(string $sType, string $sFrom)
| ||
$sType | string | |
$sFrom | string | |
{return} | array|null |
public function GetDelegates($sType,$sFrom) {
if (isset($this->aDelegates[$sType][$sFrom]['delegate'])) {
return array($this->aDelegates[$sType][$sFrom]['delegate']);
} else if($aInherits=$this->GetInherits($sFrom)) {
$aReturn=array();
foreach(array_reverse($aInherits) as $v) {
$aReturn[]=$v['inherit'];
}
return $aReturn;
}
return null;
}
public array GetDelegationChain(string $sType, string $sTo)
| ||
$sType | string | |
$sTo | string | |
{return} | array |
public function GetDelegationChain($sType,$sTo) {
$sRootDelegater = $this->GetRootDelegater($sType,$sTo);
return $this->collectAllDelegatesRecursive($sType,array($sRootDelegater));
}
Возвращает цепочку делегатов
public null|array GetInherits(string $sFrom)
| ||
$sFrom | string | |
{return} | null|array |
public function GetInherits($sFrom) {
if (isset($this->aInherits[trim($sFrom)])) {
return $this->aInherits[trim($sFrom)]['items'];
}
return null;
}
Возвращает список наследуемых классов
public null|string GetLastInherit($sFrom $sFrom)
| ||
$sFrom | $sFrom | |
{return} | null|string |
public function GetLastInherit($sFrom) {
if (isset($this->aInherits[trim($sFrom)])) {
return $this->aInherits[trim($sFrom)]['items'][count($this->aInherits[trim($sFrom)]['items'])-1];
}
return null;
}
Возвращает последнего наследника в цепочке
public array GetList($aFilter=array (
))
| ||
$aFilter | ||
{return} | array |
public function GetList($aFilter=array()) {
if ($aPaths=glob($this->sPluginsDir.'*',GLOB_ONLYDIR)) {
$aList=array_map('basename',$aPaths);
$aActivePlugins=$this->GetActivePlugins();
foreach($aList as $sPlugin) {
$this->aPluginsList[$sPlugin] = array(
'code' => $sPlugin,
'is_active' => in_array($sPlugin,$aActivePlugins)
);
/**
* Считываем данные из XML файла описания
*/
$sPluginXML = $this->sPluginsDir.$sPlugin.'/'.self::PLUGIN_XML_FILE;
if($oXml = @simplexml_load_file($sPluginXML)) {
/**
* Обрабатываем данные, считанные из XML-описания
*/
$sLang=$this->Lang_GetLang();
$this->Xlang($oXml,'name',$sLang);
$this->Xlang($oXml,'author',$sLang);
$this->Xlang($oXml,'description',$sLang);
$oXml->homepage=$this->Text_Parser($oXml->homepage);
$oXml->settings=preg_replace('/{([^}]+)}/',Router::GetPath('$1'),$oXml->settings);
$this->aPluginsList[$sPlugin]['property']=$oXml;
} else {
/**
* Если XML-файл описания отсутствует, или не является валидным XML,
* удаляем плагин из списка
*/
unset($this->aPluginsList[$sPlugin]);
}
}
}
/**
* Если нужно сортировать плагины
*/
if (isset($aFilter['order'])) {
if ($aFilter['order']=='name') {
$aPlugins=$this->aPluginsList;
uasort($aPlugins, create_function('$a,$b',"if ((string)\$a['property']->name->data == (string)\$b['property']->name->data) { return 0; } return ((string)\$a['property']->name->data < (string)\$b['property']->name->data) ? -1 : 1;"));
return $aPlugins;
}
}
return $this->aPluginsList;
}
Получает список информации о всех плагинах, загруженных в plugin-директорию
public string GetParentInherit(string $sFrom)
| ||
$sFrom | string | |
{return} | string |
public function GetParentInherit($sFrom) {
if (!isset($this->aInherits[$sFrom]['items']) or count($this->aInherits[$sFrom]['items'])<=1 or $this->aInherits[$sFrom]['position']<1) {
return $sFrom;
}
$this->aInherits[$sFrom]['position']--;
return $this->aInherits[$sFrom]['items'][$this->aInherits[$sFrom]['position']]['inherit'];
}
Получает следующего родителя у наследника. ВНИМАНИЕ! Данный метод нужно вызвать только из __autoload()
public string GetRootDelegater(string $sType, string $sTo)
| ||
$sType | string | |
$sTo | string | |
{return} | string |
public function GetRootDelegater($sType,$sTo) {
$sItem = $sTo;
$sItemDelegater = $this->GetDelegater($sType,$sTo);
while(empty($sRootDelegater)) {
if($sItem==$sItemDelegater) {
$sRootDelegater = $sItem;
}
$sItem = $sItemDelegater;
$sItemDelegater = $this->GetDelegater($sType,$sItemDelegater);
}
return $sRootDelegater;
}
Возвращает делегируемый класс
public void Inherit(string $sFrom, string $sTo, string $sSign='ModulePlugin')
| ||
$sFrom | string | |
$sTo | string | |
$sSign | string |
public function Inherit($sFrom,$sTo,$sSign=__CLASS__) {
if(!is_string($sSign) or !strlen($sSign)) return null;
if(!$sFrom or !$sTo) return null;
$this->aInherits[trim($sFrom)]['items'][]=array(
'inherit'=>trim($sTo),
'sign'=>$sSign
);
$this->aInherits[trim($sFrom)]['position']=count($this->aInherits[trim($sFrom)]['items'])-1;
}
Добавляет в стек наследника класса
public void Init()
|
public function Init() {
$this->sPluginsDir=Config::Get('path.root.server').'/plugins/';
}
Инициализация модуля
public bool SetActivePlugins(array|string $aPlugins)
| ||
$aPlugins | array|string | Список плагинов |
{return} | bool |
public function SetActivePlugins($aPlugins) {
if(!is_array($aPlugins)) $aPlugins = array($aPlugins);
$aPlugins=array_unique(array_map('trim',$aPlugins));
/**
* Записываем данные в файл PLUGINS.DAT
*/
if (@file_put_contents($this->sPluginsDir.Config::Get('sys.plugins.activation_file'), implode(PHP_EOL,$aPlugins))!==false) {
return true;
}
return false;
}
Записывает список активных плагинов в файл PLUGINS.DAT
public null|bool Toggle(string $sPlugin, $sAction $sAction)
| ||
$sPlugin | string | Название плагина(код) |
$sAction | $sAction | Действие - activate/deactivate |
{return} | null|bool |
public function Toggle($sPlugin,$sAction) {
$aPlugins=$this->GetList();
if(!isset($aPlugins[$sPlugin])) return null;
$sPluginName=func_camelize($sPlugin);
switch ($sAction) {
case 'activate':
case 'deactivate':
$sAction=ucfirst($sAction);
$sFile="{$this->sPluginsDir}{$sPlugin}/Plugin{$sPluginName}.class.php";
if(is_file($sFile)) {
require_once($sFile);
$sClassName="Plugin{$sPluginName}";
$oPlugin=new $sClassName;
if($sAction=='Activate') {
/**
* Проверяем совместимость с версией LS
*/
if(defined('LS_VERSION')
and version_compare(LS_VERSION,(string)$aPlugins[$sPlugin]['property']->requires->livestreet,'<')) {
$this->Message_AddError(
$this->Lang_Get(
'plugins_activation_version_error',
array(
'version'=>$aPlugins[$sPlugin]['property']->requires->livestreet)
),
$this->Lang_Get('error'),
true
);
return;
}
/**
* Проверяем наличие require-плагинов
*/
if($aPlugins[$sPlugin]['property']->requires->plugins) {
$aActivePlugins=$this->GetActivePlugins();
$iConflict=0;
foreach ($aPlugins[$sPlugin]['property']->requires->plugins->children() as $sReqPlugin) {
if(!in_array($sReqPlugin,$aActivePlugins)) {
$iConflict++;
$this->Message_AddError(
$this->Lang_Get('plugins_activation_requires_error',
array(
'plugin'=>func_camelize($sReqPlugin)
)
),
$this->Lang_Get('error'),
true
);
}
}
if($iConflict) { return; }
}
/**
* Проверяем, не вступает ли данный плагин в конфликт с уже активированными
* (по поводу объявленных делегатов)
*/
$aPluginDelegates=$oPlugin->GetDelegates();
$aPluginInherits=$oPlugin->GetInherits();
$iConflict=0;
foreach ($this->aDelegates as $sGroup=>$aReplaceList) {
$iCount=0;
if(isset($aPluginDelegates[$sGroup])
and is_array($aPluginDelegates[$sGroup])
and $iCount=count($aOverlap=array_intersect_key($aReplaceList,$aPluginDelegates[$sGroup]))) {
$iConflict+=$iCount;
foreach ($aOverlap as $sResource=>$aConflict) {
$this->Message_AddError(
$this->Lang_Get('plugins_activation_overlap', array(
'resource'=>$sResource,
'delegate'=>$aConflict['delegate'],
'plugin' =>$aConflict['sign']
)),
$this->Lang_Get('error'), true
);
}
}
if(isset($aPluginInherits[$sGroup])
and is_array($aPluginInherits[$sGroup])
and $iCount=count($aOverlap=array_intersect_key($aReplaceList,$aPluginInherits[$sGroup]))) {
$iConflict+=$iCount;
foreach ($aOverlap as $sResource=>$aConflict) {
$this->Message_AddError(
$this->Lang_Get('plugins_activation_overlap', array(
'resource'=>$sResource,
'delegate'=>$aConflict['delegate'],
'plugin' =>$aConflict['sign']
)),
$this->Lang_Get('error'), true
);
}
}
if($iCount){ return; }
}
/**
* Проверяем на конфликт с наследуемыми классами
*/
$iConflict=0;
foreach ($aPluginDelegates as $sGroup=>$aReplaceList) {
foreach ($aReplaceList as $sResource=>$aConflict) {
if (isset($this->aInherits[$sResource])) {
$iConflict+=count($this->aInherits[$sResource]['items']);
foreach ($this->aInherits[$sResource]['items'] as $aItem) {
$this->Message_AddError(
$this->Lang_Get('plugins_activation_overlap_inherit', array(
'resource'=>$sResource,
'plugin' =>$aItem['sign']
)),
$this->Lang_Get('error'), true
);
}
}
}
}
if($iConflict){ return; }
}
$bResult=$oPlugin->$sAction();
} else {
/**
* Исполняемый файл плагина не найден
*/
$this->Message_AddError($this->Lang_Get('plugins_activation_file_not_found'),$this->Lang_Get('error'),true);
return;
}
if($bResult) {
/**
* Переопределяем список активированных пользователем плагинов
*/
$aActivePlugins=$this->GetActivePlugins();
if($sAction=='Activate') {
/**
* Вносим данные в файл об активации плагина
*/
$aActivePlugins[] = $sPlugin;
} else {
/**
* Вносим данные в файл о деактивации плагина
*/
$aIndex=array_keys($aActivePlugins,$sPlugin);
if(is_array($aIndex)) {
unset($aActivePlugins[array_shift($aIndex)]);
}
}
/**
* Сбрасываем весь кеш, т.к. могут быть закешированы унаследованые плагинами сущности
*/
$this->Cache_Clean();
if (!$this->SetActivePlugins($aActivePlugins)) {
$this->Message_AddError($this->Lang_Get('plugins_activation_file_write_error'),$this->Lang_Get('error'),true);
return;
}
/**
* Очищаем компиленые шаблоны от Smarty
*/
$oSmarty=$this->Viewer_GetSmartyObject();
$oSmarty->clearCompiledTemplate();
}
return $bResult;
default:
return null;
}
}
Переключает состояние плагина активный/не активный
protected void Xlang(SimpleXMLElement $oXml, string $sProperty, string $sLang)
| ||
$oXml | SimpleXMLElement | XML узел |
$sProperty | string | Свойство, которое нужно вернуть |
$sLang | string | Название языка |
protected function Xlang($oXml,$sProperty,$sLang) {
$sProperty=trim($sProperty);
if (!count($data=$oXml->xpath("{$sProperty}/lang[@name='{$sLang}']"))) {
$data=$oXml->xpath("{$sProperty}/lang[@name='default']");
}
$oXml->$sProperty->data=$this->Text_Parser(trim((string)array_shift($data)));
}
Получает значение параметра из XML на основе языковой разметки
public array collectAllDelegatesRecursive(string $sType, string $aDelegates)
| ||
$sType | string | |
$aDelegates | string | |
{return} | array |
public function collectAllDelegatesRecursive($sType,$aDelegates) {
foreach($aDelegates as $sClass) {
if($aNewDelegates=$this->GetDelegates($sType,$sClass)) {
$aDelegates = array_merge($this->collectAllDelegatesRecursive($sType,$aNewDelegates),$aDelegates);
}
}
return $aDelegates;
}
Составляет цепочку делегатов
public bool isDelegated(string $sType, string $sTo)
| ||
$sType | string | |
$sTo | string | |
{return} | bool |
public function isDelegated($sType,$sTo) {
/**
* Фильтруем маппер делегатов/наследников
* @var array
*/
$aDelegateMapper=array();
foreach($this->aDelegates[$sType] as $kk=>$vv) {
if ($vv['delegate']==$sTo) {
$aDelegateMapper[$kk]=$vv;
}
}
if (is_array($aDelegateMapper) and count($aDelegateMapper)) {
return true;
}
foreach ($this->aInherits as $k=>$v) {
$aInheritMapper=array();
foreach($v['items'] as $kk=>$vv) {
if ($vv['inherit']==$sTo) {
$aInheritMapper[$kk]=$vv;
}
}
if (is_array($aInheritMapper) and count($aInheritMapper)) {
return true;
}
}
return false;
}
Возвращает true, если устано
public bool isDelegater(string $sType, string $sFrom)
| ||
$sType | string | |
$sFrom | string | |
{return} | bool |
public function isDelegater($sType,$sFrom) {
if (isset($this->aDelegates[$sType][$sFrom]['delegate'])) {
return true;
} elseif ($aInherit=$this->GetLastInherit($sFrom)) {
return true;
}
return false;
}
Возвращает true, если установлено правило делегирования и класс является базовым в данном правиле