Наследование одного екшена разными плагинами

Здесь я высказался о проблеме. Сегодня я расскажу как её решить, а точнее какие изменения внести в ядро 042 из последней транковой версии.
Проблема эта однажды коснется почти каждого т.к. она весьма серьезная и с ней столкнутся — раз плюнуть, поэтому пост заносим в избранное.

Коротко напомню суть проблемы — если два разных плагина наследуют один общий екшен (например ActionSettings), и оба плагина выводят что-то в шаблон, то один из плагинов (который был активирован первым) завершится ошибкой не нахождения шаблона.

Fatal error: Uncaught exception 'Exception' with message 'Can not find the template: actions/ActionSettings/abc.tpl' in лалала


Решение для LiveStreet версии 0.4.2. Перед тем как вносить изменения делайте резервные копии!
Решение затрагивает всего 3 файла в папке engine:
2 файла — папка classesActionPlugin.class.php и Action.class.php
1 из modules/pluginPlugin.class.php.

UPD:
Все изменения я внес в стандартные файлы ядра ЛС 042 и сохранил в одном архиве с сохранением структуры папок, так что можно файлы просто скопировать поверх от корня сайта.

Все изменения данного поста в этом архиве.

Итак, на первое:
Из engine/classes/ActionPlugin.class.php полностью удаляем функции
protected function SetTemplateAction($sTemplate)

и
public function GetTemplate()


Второе блюдо:
В engine/classes/Action.class.php

Функцию
protected function SetTemplateAction($sTemplate) 

заменяем на

protected function SetTemplateAction($sTemplate) {
  $aDelegates = $this->Plugin_GetDelegationChain('action',$this->GetActionClass());
  $sActionTemplatePath = $sTemplate.'.tpl';
  foreach($aDelegates as $sAction) {
    if(preg_match('/^(Plugin([\w]+)_)?Action([\w]+)$/i',$sAction,$aMatches)) {
      $sTemplatePath = $this->Plugin_GetDelegate('template','actions/Action'.ucfirst($aMatches[3]).'/'.$sTemplate.'.tpl');
      if(empty($aMatches[1])) {
        $sActionTemplatePath = $sTemplatePath;
      } else {
        $sTemplatePath = Plugin::GetTemplatePath($sAction).$sTemplatePath;
        if(is_file($sTemplatePath)) {
          $sActionTemplatePath = $sTemplatePath;
          break;
        }
      }
    }
  }
    $this->sActionTemplate = $sActionTemplatePath;
}

и функцию

public function GetTemplate()

заменяем на


public function GetTemplate() {
  if (is_null($this->sActionTemplate)) {
      $this->SetTemplateAction($this->sCurrentEvent);
  }
  return $this->sActionTemplate;
}


Третье:
В engine/modules/plugin/Plugin.class.php добавить в конце:


public function GetInherits($sFrom) {
  if (isset($this->aInherits[trim($sFrom)])) {
    return $this->aInherits[trim($sFrom)]['items'];
  }
  return 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)) {
    return array_map(create_function('$aInherit','return $aInherit["inherit"];'),array_reverse($aInherits));
  }
  return null;
}

public function GetDelegationChain($sType,$sTo) {
  $sRootDelegater = $this->GetRootDelegater($sType,$sTo);
  return $this->collectAllDelegatesRecursive($sType,array($sRootDelegater));
}

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 function collectAllDelegatesRecursive($sType,$aDelegates) {	
  foreach($aDelegates as $sClass) {
    if($aNewDelegates=$this->GetDelegates($sType,$sClass)) {
      $aDelegates = array_merge($this->collectAllDelegatesRecursive($sType,$aNewDelegates),$aDelegates);
    }
  }
  return $aDelegates;
}


После выполненных действий шаблоны начали работать.

Надеюсь кому-то поможет.

UPD:
Все изменения данного поста в этом архиве.

12 комментариев

avatar
Поделились бы ходом решения, мыслями, почему именно так делали, понимаю что это программист должен знать, но понять где и что исправить не под силу каждому, особено тому кто начинает не с ООП. вообщем чтобы код был читабельным нужно не только использовать правильную структуру но и не забывать про комментарии.
avatar
здесь особо комментировать нечего. в прошлом посте я рассказал о проблеме, поэтому решение просто нужно принять «как есть». Здесь нет ничего супер экстраординарного, это просто багфикс ядра.
avatar
Для вас да, тупо вставить и заменить код любой может
а почему именно этот код? и туда? расскажите словами человека который понимает, что кто делегирует, наследует? один мудрый человек сказал, расскажи другим — поймешь сам.понимаю что теперь все будет работать как нужно, но словами рассказать что же было почему не работало рассказать сможешь??
avatar
я все детально описал в предыдущем топике, что плагин который наследует системный класс ещё с одним плагином и который был активирован по очереди вторым — работает, а первый плагин — нет, т.к. шаблоны первого плагина ищутся в папке второго. Данный фикс избавляет от этой проблемы и основан на транковой версии движка.

Почему мне надо копипастить это ещё в этом топике? Те, кто столкнутся с этой проблемой используют патч и забудут о ней.
avatar
а почему именно этот код?
вот читать нужно внимательно кстати, в топике сказано почему именно этот код.
и туда
ну простите, нужно хотя бы чуть понимать в программировании почему именно «туда». Я же не могу людям, которые работают в других сферах объяснять тонкости работы кода, которой им сложно понять. А рассказывать что мы «редактируем модуль Plugin.class.php потому что он отвечает за работу с плагинами, где собственно проблема — по мне это чересчур. Пост ориентирован на программистов, т.к. они будут заниматься этим, т.к. просто пользователь определить эта ли ошибка у него на хостинге или нет — не сможет.
avatar
Я вас отлично понял, а Вы меня нет, писать комменты к функциям это очень полезно.читать код не нужно быть программистом, достаточно быть кодером. Вот что я хотел так вот пример:
вы пишете что нужно заменить вот это
public function GetTemplate() {
		if (is_null($this->sActionTemplate)) {
			$sActionClass=$this->GetActionClass();
			/**
			 * Если класс не является делегатом плагина, устанавлваем шаблон по умолчанию.
			 * В случае делегирования, проверяем сначала имеет ли указанный плагин замену для шаблона.
			 */
			if(!$this->Plugin_isDelegated('action',$sActionClass)) {
				$this->sActionTemplate='actions/'.$sActionClass.'/'.$this->sCurrentEvent.'.tpl';	
			} else {
				$sDelegater = $this->Plugin_GetDelegater('action',$sActionClass);
				$sTemplatePath = Plugin::GetTemplatePath($this->Plugin_GetDelegateSign('action',$sDelegater));
				
				$this->sActionTemplate = is_file($sFile=$sTemplatePath.'actions/'.$sDelegater.'/'.$this->sCurrentEvent.'.tpl')
					? $sFile
					: 'actions/'.$sDelegater.'/'.$this->sCurrentEvent.'.tpl';
			}
		}
		return $this->sActionTemplate;
	}


на это
public function GetTemplate() {
  if (is_null($this->sActionTemplate)) {
      $this->SetTemplateAction($this->sCurrentEvent);
  }
  return $this->sActionTemplate;
}


Вот меня и всех интересует, почему имено на это? с чего вы взяли что Ваш код правельным будет, то что работает это не говорит что «правильно», поясните что происходило в функции до Ваших изменений и после?, прокомментируйте каждую строчку кода?
avatar
Вот меня и всех интересует, почему имено на это? с чего вы взяли что Ваш код правельным будет, то что работает это не говорит что «правильно», поясните что происходило в функции до Ваших изменений и после?, прокомментируйте каждую строчку кода?
я вам ещё раз намекаю — перечитайте пост — там 100% сказано почему этот код, я не стебусь.
avatar
Вот меня и всех интересует
Вас — вижу, да. А вот «всех» — нет. Только вам не понятно. Может тогда стоит не говорить за «всех»?
avatar
Почему Вы упрямитесь прокомментировать свои поделки, мысли? строчки кода?
ЗЫ. остальные пока спят))
avatar
Здесь я высказался о проблеме. Сегодня я расскажу как её решить, а точнее какие изменения внести в ядро 042 из последней транковой версии.
Больше дискуссировать не имею желания.
Доброй ночи.
avatar
Хорошо, но у мну только день начался!
avatar
а у нас ночь. давно -_-
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.