Руководство по созданию плагина для v.0.4 на примере "Лента друзей"

82
Предисловие

Что такое плагины — читайте здесь.
По мотивам этого, выполняю обещание — привожу руководство как подобное сделать в виде плагина. Всех тонкостей в одной заметке не расскажешь, но основное постараюсь изложить.

Примечание. Долго не публиковал этот материал, держал в черновиках — на случай «мало-ли-что-измениться». Но думаю, кардинальных изменений в механизме плагинов в ближайшем релизе уже не будет.

Пошаговая схема:
1. Создаем директорию и основные файлы плагина

Назовем плагин Friends Feed, но для краткости в названиях файлов и директорий будем использовать просто friends. Поэтому создаем директорию friends в директории plugins.

Вкладываем туда файлы PluginFriends.class.php и plugin.xml

PluginFriend.class.php

<?php
/**
 * Плагин предназначен для выведения пользователю списка топиков его друзей
 * 
 * by Alex Kachayev <kachayev@gmail.com>
 */
class PluginFriends extends Plugin {
	/**
	 * Активация плагина
	 * В принципе, здесь нам делать ничего не нужно
	 */
	public function Activate() {
		return true;
	}
	
	/**
	 * Инициализация плагина
	 */
	public function Init() {
		$this->Viewer_AddMenu('blog',Plugin::GetTemplatePath(__CLASS__).'/menu.blog.tpl');
	}
	
	/**
	 * Деактивация плагина
	 * В принципе, тут тоже ничего не нужно делать
	 */
	public function Deactivate() {
		return true;
	}
}


Примечание. Функции Activate(), Deactivate() можно было и не создавать, добавил просто чтоб напомнить о возможности их использования. В функции Init() «всплывает» достаточно интересный момент — замена стандартного меню, но об этом мы поговорим чуть позже.

Plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
	<name>
		<lang name="default">Friends Feed</lang>
		<lang name="russian">Лента Друзей</lang>
	</name>
	<author>
		<lang name="default">Alex Kachayev</lang>
		<lang name="russian">Алексей Качаев</lang>
	</author>
	<homepage>http://kachayev.ru/</homepage>
	<version>0.8.1</version>
	<requires>
		<livestreet>0.4.0</livestreet>
		<plugins>

		</plugins>
	</requires>
	<description>
		<lang name="default">Show topics that are wrote by your friends.</lang>
		<lang name="russian">Вывод записей друзей отдельной лентой.</lang>
	</description>
	<delegate>
		<module></module>
		<action></action>
		<template></template>
		<entity></entity>
	</delegate>
</plugin>


Если все правильно сделали, то с этого момента плагин существует и формально функционирует. Т.е. зайдя в панель управления плагинами (/admin/plugins) вы уже можете увидеть новый «пункт» и произвести активацию\деактивацию. Правда нам это пока ничего не даст, ибо функционала еще не предусмотрено =)

2. Роутинг и конфигурация

Учтем, что лента друзей должна быть доступна по определенному URL. Например, /friends. Значит нам нужно добавить новое правило роутинга. Сделать это нужно в файле конфигурации плагина. Создаем директорию /friends/config/ и вкладываем туда файл config.php — эта конфигурация будет автоматически загружена, если плагин активирован администратором проекта.

Пока от нас требуется только указать новый «пункт» роутинга. Сделаем это вызовом Config::Set(). Для демонстрации работы конфигурации плагина, я также добавлю параметр работы плагина — количество выводимых записей на страницу (в учебных целях, в рабочем проекте я бы воспользовался значением этого параметра для остальных экшенов).

config.php:

/**
 * Плагин предназначен для выведения пользователю списка топиков его друзей
 * 
 * by Alex Kachayev <kachayev@gmail.com>
 */

$config['per_page']   = 10;  // Число топиков на одну страницу ленты

Config::Set('router.page.friends', 'PluginFriends_ActionFeed');

return $config;


3. Action для вывода записей и модуль

Для начала сделаем модуль для получения записей, написанных друзьями. В папке /plugins/friends/ создаем директорию /classes/modules/friends и вкладываем туда файл Friends.class.php:


<?php

class PluginFriends_Friends extends Module {
		public function Init() {
			
		}
        /**
         * Получает число новых топиков в ленте друзей
         *
         * @return array
         */
        public function GetCountTopicsFriendsNew($sUserId) {
        	$sDate=date("Y-m-d H:00:00",time()-Config::Get('module.topic.new_time'));
			$aFriends = $this->User_GetUsersFriend($sUserId);
        	
        	if(!is_array($aFriends) or count($aFriends)==0) {
        		return 0;
        	}
        	
        	$aFilter=array(
	        	'user_id' => array_keys($aFriends),
	        	'topic_publish' => 1,
	        	'topic_new' => $sDate,
        	);

        	$s=serialize($aFilter);
        	if (false === ($data = $this->Cache_Get("topic_friend_count_{$s}"))) {
        		$data = $this->Topic_GetCountTopicsByFilter($aFilter);
        		$this->Cache_Set($data, "topic_friend_count_{$s}", array('topic_update','topic_new'), 60*5);
        	}
        	return  $data;
        }
        /**
         * Получает все топики в ленте друзей
         *
         * @return array
         */
        public function GetTopicsFriends($sUserId,$iPage,$iPerPage) {
        	/**
        	 * Получаем идентификаторы друзей пользователя
        	 */
        	$aFriends = $this->User_GetUsersFriend($sUserId);
        	
        	if(!is_array($aFriends) or count($aFriends)==0) {
        		return array('count'=>0, 'collection'=>array());
        	}
        	
        	$aFilter=array(
	        	'user_id' => array_keys($aFriends),
	        	'topic_publish' => 1,
	        	'blog_type' => array('open','personal')
        	);
        	
        	return $this->Topic_GetTopicsByFilter($aFilter,$iPage,$iPerPage);
        }
        
        public function Shutdown() {
        	
        }
}
?>

Как видите, в этом файле, мы создаем новый модуль PluginFriends_Friends, предназначенный для: а) получения списка топиков в ленте друзей, б) получения количество топиков в ленте друзей. По сути ничего необычно, единственное отличие от простого модуля — приставка в названии с указанием на плагин Friends.

Создаем экшен для обработки вывода записей Ленты Друзей. Для этого в директории /friends/classes/ создаем директорию actions и вкладываем туда файл ActionFeed.class.php:


<?php

class PluginFriends_ActionFeed extends ActionPlugin {
        /**
         * Главное меню
         *
         * @var unknown_type
         */
        protected $sMenuHeadItemSelect='blog';
        /**
         * Меню
         *
         * @var unknown_type
         */
        protected $sMenuItemSelect='index';
        /**
         * Субменю
         *
         * @var unknown_type
         */
        protected $sMenuSubItemSelect='friends';
        /**
         * Число новых топиков
         *
         * @var unknown_type
         */
        protected $iCountTopicsNew=0;
        /**
         * Число новых топиков в ленте друзей
         *
         * @var unknown_type
         */
        protected $iCountTopicsFriendsNew=0;
        /**
         * Число новых топиков в коллективных блогах
         *
         * @var unknown_type
         */
        protected $iCountTopicsCollectiveNew=0;
        /**
         * Число новых топиков в персональных блогах
         *
         * @var unknown_type
         */
        protected $iCountTopicsPersonalNew=0;
        
        /**
         * Инициализация
         *
         */
        public function Init() {                        
        	$this->Viewer_AddBlocks('right',array('stream','tags','blogs'));
        	/**
        	 * Подсчитываем новые топики
        	 */

        	$this->iCountTopicsCollectiveNew=$this->Topic_GetCountTopicsCollectiveNew();
       		$this->iCountTopicsPersonalNew=$this->Topic_GetCountTopicsPersonalNew();
        	$this->iCountTopicsFriendsNew=$this->PluginFriends_Friends_GetCountTopicsFriendsNew($this->User_GetUserCurrent()->getId());
        	$this->iCountTopicsNew=$this->iCountTopicsCollectiveNew+$this->iCountTopicsPersonalNew;
        }
        /**
         * Регистрация евентов
         *
         */
        protected function RegisterEvent() {
                $this->AddEventPreg('/^(page(\d+))?$/i','EventFriends');
        }

        
        /**********************************************************************************
         ************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
         **********************************************************************************
         */
        
        /**
         * Реализация евента
         *
         */
        protected function EventFriends() {
                /**
                 * Меню
                 */
                $this->sMenuSubItemSelect='friends';
                /**
                 * Передан ли номер страницы
                 */
                $iPage=$this->GetEventMatch(2) ? $this->GetEventMatch(2) : 1;
                /**
                 * Получаем список топиков
                 */                                     
                $aResult=$this->PluginFriends_Friends_GetTopicsFriends($this->User_GetUserCurrent()->getId(),1,10);
                $aTopics=$aResult['collection'];
                /**
                 * Формируем постраничность
                 */
                $aPaging=$this->Viewer_MakePaging($aResult['count'],$iPage,10,4,Router::GetPath('friends'));
                /**
                 * Загружаем переменные в шаблон
                 */
                $this->Viewer_Assign('aTopics',$aTopics);
                $this->Viewer_Assign('aPaging',$aPaging);               
                /**
                 * Устанавливаем шаблон вывода
                 */
                $this->SetTemplateAction('friends');
        }
        /**
         * При завершении экшена загружаем переменные в шаблон
         *
         */
        public function EventShutdown() {
        	$this->Viewer_Assign('sMenuHeadItemSelect',$this->sMenuHeadItemSelect);
        	$this->Viewer_Assign('sMenuItemSelect',$this->sMenuItemSelect);
        	$this->Viewer_Assign('sMenuSubItemSelect',$this->sMenuSubItemSelect);
        	$this->Viewer_Assign('iCountTopicsNew',$this->iCountTopicsNew);
        	$this->Viewer_Assign('iCountTopicsFriendsNew',$this->iCountTopicsFriendsNew);
        	$this->Viewer_Assign('iCountTopicsCollectiveNew',$this->iCountTopicsCollectiveNew);
        	$this->Viewer_Assign('iCountTopicsPersonalNew',$this->iCountTopicsPersonalNew);
        }
}
?>


Это так же самый обычный по виду экшен. Ключевые моменты:
— название PluginFriends_ActionFeed содержит указание на плагин Friends;
— класс экшена унаследован от ActionPlugin.

4. Добавляем шаблоны и пункт меню

Но, сейчас этот экшен работать не будет — нет пока шаблона для работы. С шаблонами есть маленький ньюанс — плагин может использоваться с различными шаблонами (skin). Поэтому чтобы у пользователей не возникало потом проблем с вашим плагином, плагин по умолчанию поддерживает мульти-skin. По умолчанию будет использован skin default. Поскольку наша задача не прорисовать как можно больше вариантов, а посмотреть на общую схему работы, то создаем директорию /templates/skin/default/ и туда вкладываем шаблон нашего экшена: actions/ActionFeed/friends.tpl.

Шаблон максимально простой:

{include file='header.tpl' menu='blog'}
{include file='topic_list.tpl'}
{include file='footer.tpl'}


Осталось последнее — создать пункт меню для попадания в Ленту друзей. Для того, чтобы это сделать нам нужно добавить доп. пункт в меню menu.blog.tpl. Мы сделаем это так: копируем файл menu.blog.tpl из шаблона new движка в директорию /plugins/friends/templates/skin/default/menu.blog.tpl. В этом файле в первую секцию добавим следующий код:


<li {if $sMenuSubItemSelect=='friends'}class="active"{/if}><div><a href="{router page='friends'}">{$aLang.plugin_friends_menu_title}</a>{if $iCountTopicsFriendsNew} +{$iCountTopicsFriendsNew}{/if}</div></li>


Именно это меню подключается в шаблоны в функции инициализации плагина Init() (об этом мы уже говорили):

$this->Viewer_AddMenu('blog',Plugin::GetTemplatePath(__CLASS__).'/menu.blog.tpl');


Последний штрих — языковой файл /templates/language/russian.php с единственной текстовкой:

<?php
/**
 * Русский языковой файл плагина Friends
 */
return array(
	'plugin_friends_menu_title' => 'Лента друзей'
);
?>


5. The End

Собственно и все. Кажется, ничего не забыл. Если остались вопросы — с радостью отвечу.
  • +18
  • 21 февраля 2010, 03:39
  • kachayev

Комментарии (101)

RSS свернуть / развернуть
большое спасибо

тоже неплохое изобретение…
0
спасибо за мануал, но кат бы в любом случае не помешал :-)
+1
  • avatar
  • kruft
  • 21 февраля 2010, 08:17
=) Подрезал.
0
Спасибо! Вчера мне этот мануал бы не помешал :)))
0
  • avatar
  • noonv
  • 21 февраля 2010, 10:28
Есть подозрение, что твой пост и подтолкнул Алексея — мол, пора уже, из черновиков на свет белый доставать. :)
+1
Угу.
0
:)))
0
Собственно и все. Кажется, ничего не забыл. Если остались вопросы — с радостью отвечу.
Где сам плагин то скачать для 0.4? =)
0
  • avatar
  • Mmka
  • 21 февраля 2010, 12:21
Это конструктор-лего. Суть же была не в конечном результате — а в самом процессе создания. После выхода v.0.4 запакую и выложу в каталог модулей.
+1
Алексей, была такая мелочь еще: конфиг-файл плагина обязательно должен был возвращать массив. Т.е. даже если мне просто надо было роутинг задать через Config::Set('router.page.xxx', ...);, то все равно приходилось возвращать пустой массив. Пишу в прошедшем времени, т.к. не проверял в последних релизах, а так и ставлю пустой массив на выходе. В общем-то, фигня, конечно, но лучше бы это дело как-то проверять при загрузке конфига.
0
Пишу в прошедшем времени
В текущем времени все осталось так же: конфиг должен возвращать массив.
0
Спасибо за руководство. Пробую.

Вкладываем туда файлы PluginFriend.class.php
PluginFriends.class.php
0
языковой файл /templates/language/russian.tpl
russian.php
0
Спс, поправил.
0
Можно пример, как включить в состав плагина свой блок? Как он должен называться? И где он должен лежать?
0
Хороший плаг. Спасибо :)
Хотя, возможно, стоило бы для «руководства» взять плагин пообширнее охватывающий логику плагинов — с делегированием, например — это ж одна из основных фишек. Думаю в ближайшее время надо найти время что-нибудь из поделок для 0,31 переделать в плагин для 0,4, постараюсь захватить что-нибудь что еще не применяли в примерах.
+1
На самом деле, для меня и делегирование, и все остальное — вполне «обыденно». Мне сложно сказать какая из этих частей функционала является более важной.

Поэтому сделал то, что «заказали» в прошлой публикации =)
0
Я тоже не имел ввиду важность какой либо части, я имел ввиду другое — плагины они же на самом деле круче, чем просто способ не правя системные файлы встроить дополнительный функционал, так и надо это показать :) Ту же ленту друзей и на 0,31 можно вообще не затрагивая системные файлы сделать, ну да, только менюшку вписать в шаблон:)
0
Спасибо, теперь почти все для себя прояснил.
Один вопрос, как правильно прописывать делегирование внутри ?
0
  • avatar
  • Ajaxy
  • 26 февраля 2010, 04:18
<delegate></delegate>
0
«Внутри» — ты имеешь ввиду по коду? Вот так:
$this->Plugin_Delegate()
0
внутри xml, тегов


<delegate></delegate>


я не нашел нигде, пробывал
<delegate>
 <action>
  <from>ActionSettings.class.php</from>
  <to>ActionSettings.class.php</to>
 </action>
</delegate>

не помогло. как правильно? :)
+2
Присоединяюсь к вопросу — не нашел в коде вообще работу с секцией
<delegate></delegate>
считываемой из xml-ки. Невнимательно искал или еще не реализовано?
+3
Не пойму, почему новые показываются только когда переходишь на ленту?
0
  • avatar
  • roose
  • 26 февраля 2010, 10:20
Потому что так сделано.
Для вывода количества новых вне экшена Friends, нужно задавать отдельно функционал в каждом из экшенов, где нужно это показывать. Например, с помощью механизма хуков.
0
Уже понял, и сделал просто добавив в index и blog, жаль только что нельзя это сделать из плагина.
А про хуки примера не найдется?
0
нельзя это сделать из плагина
Можно!
Для этого нужно внутри плагина создать хук, в котором получать количество новых записей в ленте, передавать их во Viewer. И повесить хук на shutdown экшенов index, blog
0
Если бы еще знать на что и как ставить хуки)
0
я у себя вот так сделал
<?php
/**
 * Хук для плагина Friend Feed
 */
class PluginFriends_HookFriends extends Hook {

        /**
         * Регистрируем хук на action_event_index_after
         *
         * @return void
         */
        public function RegisterHook() {
                if ($this->User_IsAuthorization()) {
                        $this->AddHook("action_event_index_after", "setCountTopicsFriendsNew", __CLASS__);
                }
        }

        /**
         * Получаем количество новых записей в френдленте и передаем их в Viewer
         *
         * @param array $aVars
         */
        function setCountTopicsFriendsNew($aVars) {
                $this->Viewer_Assign('iCountTopicsFriendsNew', $this->PluginFriends_Friends_GetCountTopicsFriendsNew($this->User_GetUserCurrent()->getId()));
        }
}
0
Можно немного подробнее, не могу найти где описано событие 'action_event_index_after'? В текущем движке 0.4 не нашел его, однако если такой хук добавить, то он работает в экшене индекс (вот тут большая просьба пояснить как, дефолтное событие?). Если повесить его на 'init_action' — работает в любом экшене.
0
разобрался
0
а зачем на шутдаун экшена blog его цеплять?
0
А у плагина могут быть собственные блоки? Я имею ввиду, можно ли складывать плагиновские блоки вместе с остальными файлами плагина в site.ru/plugins/my_plugin/classes/blocks? Или он обязательно должны быть в site.ru/classes/blocks?
0
Да и еще одно интересно, может ли плагин в себе иметь скрипты для обработки ajax запросов. А то у мне пока выдает, что атаковали хакеры.

У кого-нибудь получалось прикрутить к плагину скрипты для обратки ajax запросов?
0
Получилось. Надо обязательно среди прочих параметров передавать параметр security_ls_key со значением LIVESTREET_SECURITY_KEY.

Например, добавлять к адресу серверного скрипта:
url+'?security_ls_key='+LIVESTREET_SECURITY_KEY
0
я об этом писал здесь
+2
Можно запускать блоки из директории плагинов. Принцип с именами тот же самый.
0
а можно пример? не очень понятно…
0
разобрался:
Config::Set('block.rule_bill', array(
  'action'  => array(
    'event', 
    'place'
  ),
  'blocks'  => array(
    'right' => array('stream','tags','blogs','places'=>array('params'=>array('plugin'=>'bill')))
  )
));
0
Огромное спасибо за информацию!
0
нужно ещё сделать, чтобы гости не видели в меню пункт «Лента друзей» и при переходе по ссылке видели не пустую страницу, а сообщение о ошибке
0
1) Ошибка в 49-ой строке файла /engine/classes/ActionPlugin.php
Т.к. $this->GetActionClass() содержит значение из $aConfig['route]['page'][{action}], то вместо
preg_match('/^Plugin([\w]+)_Action([\w]+)$/i',$this->GetActionClass(),$aMatches);
должно быть
preg_match('/^Action([\w]+)$/i',$this->GetActionClass(),$aMatches);
иначе возникает ошибка.
Соответственно появится ошибка и в 54-ой строке, где $aMatches[1] будет содержать не то, что нужно.
То же самое в 95-ой строчке.

2) Обычно делегирование нужно для модифицирования какого-то файла, поэтому он чаще всего лежит по аналогичному пути (в папке плагина) и имеет такое же имя, как и заменяемый аналог. На мой взгляд есть смысл автоматизировать прописывание этого пути.
Чаще всего будет представлять из себя что-то вроде

protected $aDelegates=array(
  'action'  =>array(
    'ActionSettings' => 'PluginProtypes_ActionSettings',
    'ActionRegistration' => 'PluginProtypes_ActionRegistration',
  ),
  'template'=>array(
    'actions/ActionSettings/profile.tpl' => '../../../plugins/protypes/templates/skin/new/actions/ActionSettings/profile.tpl',
    'actions/ActionRegistration/index.tpl' => '../../../plugins/protypes/templates/skin/new/actions/ActionRegistration/index.tpl',
  )
);

На мой взгляд, всё это лучше бы выглядело, например, так:

protected $aDelegates=array(
  'action'  =>array(
    'ActionSettings' => '#__ActionSettings',
    'ActionRegistration' => '#__ActionRegistration',
  ),
  'template'=>array(
    'actions/ActionSettings/profile.tpl' => '#__actions/ActionSettings/profile.tpl',
    'actions/ActionRegistration/index.tpl' => '#__actions/ActionRegistration/index.tpl',
  )
);


3) Я не нашел возможности делегировать темплейты, которые подключаются динамически — из других темплейтов. Например, header_top.tpl, paging.tpl, topic_list.tpl. Этого очень не хватает, есть ли возможность что-то придумать для таких ситуаций?
+1
3. Делегирования динамически подключаемых шаблонов нет. Для этого нужно лезть внутрь Smarty.
0
а что насчет (2)?
+1
Интересная мысль! Только можно вообще без решетки, а просто с подчеркивания начинать. Т.е., если есть плагин MyPlugin и там делегирование описано так:
'ActionSettings' => '_ActionSettings'

то подразумевается, что полная форма записи такая:
'ActionSettings' => 'MyPlugin_ActionSettings'


Вот только плохо, что сам модуль Plugin нельзя делегировать :(
0
'ActionSettings' => '_ActionSettings'

Я только не пойму, зачем тогда вообще что-то указывать? =) Можно вспомнить Ruby On Rails и пойти по пути COC — если в качестве делегата ничего не указано — значит делегатов является одноименный ресурс из плагина, который производит делегирование.
0
Это конечно здорово, но можно предположить, что в случае с темплейтами имя файла может и не быть идентичным, а вот длинный относительный путь от одной папки с шаблонами до другой — не очень красиво :)
Думаю, стоит реализовать оба варианта.
0
COC как раз и предполагает два пути
0
С РоР не работал толком, поэтому для меня лично эта аналогия не катит. Если явно не указывать, то как? По имени самого плагина? Или перебирать экшены (модули, сущности), которые входят в состав плагина и сравнивать их с оригинальными компонентами?
0
просто, к примеру вот так:
'template'=>array(
    'actions/ActionSettings/profile.tpl',
    'actions/ActionRegistration/index.tpl',
  )

то есть будет подразумеваться, что неуказанный делегат лежит в папке /plugins/myplugin/templates/skin/myskin/.
0
Посмотри как я сделал это для модулей, экшенов и сущностей: в XML вместо

<delegate>
   <module>
      <item>
          <from>User</from>
          <to>PluginTest_User</to>
      </item>
   </module>
</delegate>

достаточно написать:
User



Фактически я указываю только название модуля, который хочу подменить и все. Рас я не указал явно делегат — значит считаем, что мой таргет имеет аналогичное с исходным расположение и название — добавляем в начало приставку и все.
0
А вы дайте доступ к объекту Смарти, глядишь, кто-то что-то и придумает ;)
+1
Насчет (1): ошибка была из-за того, что Router::GetActionClass() возращает имя экшена без учета делегирования.
Возможное решение: добавить на 162-ой строчке файла /engine/classes/Router.class.php сохранение нового названия экшена, если учитывается делегирование:
$sActionClass=$this->Plugin_GetDelegate('action',$sActionClass);
self::$sActionClass = $sActionClass;

Создал тикет.
0
создал топик с остальными фиксами и предложениями:
0
0
3. теперь должен заработать
+1
вот это отличная новость!
0
Проверил, работает, спасибо.
Еще бы сделали чтобы можно было делегировать темплейт блоков, например block.stream.tpl, отдельно его элементы (block.stream_comment.tpl) можно делегировать, но саму основу нет.
Как понимаю всего то надо в smarty_insert_block строчку
$sBlockTemplate = 'block.'.$aParams['block'].'.tpl';
заменить на
$sBlockTemplate = Engine::getInstance()->Plugin_GetDelegate('template','block.'.$aParams['block'].'.tpl');

у меня так заработало.
+2
Теперь можно использовать короткую запись:
<template>
	<item>
		<from>actions/ActionProfile/whois.tpl</from>		
	</item>
	<item>
		<from>actions/ActionBlog/index.tpl</from>
		<to>_actions/ActionBlog/index_new.tpl</to>
	</item>
</template>
+1
ещё одно замечание. в текущей реализации ссылку на ленту друзей видят все пользователи (и гости в том числе), но у гостей она ведь не работает.

поэтому я добавил у себя проверку в шаблоне при выводе кнопки
{if $oUserCurrent}
                                                <li {if $sMenuSubItemSelect=='friends'}class="active"{/if}>
                                                        <div><div><div>
                                                                <a href="{router page='friends'}">{$aLang.plugin_friends_menu_title}</a>{if $iCountTopicsFriendsNew} +{$iCountTopicsFriendsNew}{/if}
                                                        </div></div></div>
                                                </li>
                                                {/if}


и в экшене
/**
         * Инициализация
         *
         * @return void
         */
        public function Init() {
                // Закрываем страницу для неавторизированных пользователей
		if(!$this->User_IsAuthorization()) {
			return parent::EventNotFound();
		}


может я что не так делаю. поправьте тогда
0
и в инит плагина ещё добавил
$this->Viewer_Assign('oUserCurrent', $this->User_GetUserCurrent());
0
ещё одно замечание. в текущей реализации
Я знаю, что в этом плагине еще много чего можно доделать, он был написал для того, чтобы показать сам процесс создания плагина. А дальше — полет вашей фантазии и творчества.
0
я понимаю. но плагин получился полезный и я уже несколько недель использую его на cookorama.net
предлагаю вынести его в отдельный репозиторий и развивать дальше
0
Плагин буду куда-то выносить и развивать только после выхода v.0.4 =) Пока развиваю ядро.
+1
Спасибо
0
большое спасибо за пример написания плагина

в экшене небольшая неточность:

<?php

class PluginFriends_ActionFeed extends ActionPlugin {
        /**
         * Главное меню
         *
         * @var unknown_type
         */
        protected $sMenuHeadItemSelect='blog';
        /**
         * Меню
         *
         * @var unknown_type
         */
        protected $sMenuItemSelect='index';


в результате сабменю выводится от индекса, надо:

protected $sMenuItemSelect='friends';
0
хорошо бы добавить вывод топиков только из тех блогов, на которые подписан. Это, мне кажется, куда важнее, чем топики друзей, т.к. человек подключился к 10-ти блогам, и потом может в отдельном разделе смотреть обновления их этих блогов.
+1
AddMenu вместо добавления пункта в меню, заменяет его полностью на menu.blog.tpl.
$this->Viewer_AddMenu('blog',Plugin::GetTemplatePath(__CLASS__).'/menu.blog.tpl');

livestreet v0.4.1
0
А как ссылку на ленту друзей поместить в профиль пользователя? Т.е. имеется в виду, чтобы она была видна и доступна у каждого пользователя и ей могли пользоваться и другие пользователи сайта? Зашел к другу — увидел у него ленту — ознакомился — добавил себе заинтересовавших тебя авторов…
0
Интересная задумка… надо подумать…
0
будет ли этот плагин оформлен и выложен как готовый плагин?
0
плагин «Аудиозаписи» для 0.4.2
livestreet.ru/blog/4777.html
-2
для версии 4.2 небольшая поправка… имя класса поправить PluginFriends_Friends ибо вылетает error'ка
Fatal error: Class 'PluginFriends_ModuleFriends' not found in X:\home\myblog\www\engine\classes\Engine.class.php on line 162
0
А что именно то нужно поправить, имена классов и т.п. я уже изменил с Friends на Fri… и всё-равно та же ошибка…
0
в файле plugins\friends\classes\modules\friends\Friends.class.php имя класса PluginFriends_Friends изменить на PluginFriends_ModuleFriends
0
netlanc, спасибо!
0
Спасибо автору! Только что реализовал у себя — вроде работает нормально (пока наполнения полноценного нету у сайта).

Очень полезная вещь. Странно, что такой функции у LS нету изначально. Хотя с другой стороны — хорошо, когда есть куда развиваться.

Еще раз спасибо!
0
  • avatar
  • UJey
  • 31 января 2011, 03:38
Товарищ, мы узнали что вам все же удалось реализовать написанное тут без багов, не могли бы вы поделится своей сборкой?
0
кто мы? и о каких багах идет речь?
0
Мы это множество людей которые ищут готовое решение. Я лично столкнулся с тем что некоторые плагины стали вылетать. Пришлось править код для 4.2 Но так ни чего и не получилось. Хотел попросить тебя выложить архивом, есле у тебя получилась эта задумка.
0
Готов выложить свой вариант кода (всего плагина). Но думаю правильно будет сделать следующим образом:
1. скажите мне какие баги встречаются
2. я проверю свой код (и проект) на наличие таковых, чтобы не выкладывать код, который не факт, что работает правильно.
3. исправляю баги, если такие будут найдены.
4. выкладываю здесь ссылку на архив.
0
Вы совершенно правы.
Могу сказать за себя, ставил все на 4.2
'plugin_friends_menu_title' => 'Лента друзей'

Не отображается в меню…
Пытался поставить в Профиль, но тоже какой-то косяк. Скорее всего кривые руки))… лечу их активным чтением документации.
0
Так если дело в этом — я вручную в шаблон меню (на главной) вставил ссылку на «ленту друзей».
0
Я поставил… не пашет.
В логе идет ошибка. Собрал криво плагин, от того и прошу его, чтоб разобраться что и куда не так засунул-то в итоге.
0
Вот ссылка на плагин в том виде, в котором он у меня работает.
www.ex.ua/view_storage/454673494809

Сразу скажу, что LS допиливал, поэтому не все может быть стандартно…

Попробуй.
0
Ща гляну… спасибо.
0
Пашет но глюканул весь нав хедер… и поиск куда-то исчез после активации.
0
Заменил пару строк в шаблоне под него и все запахало, как родное))
Спасибо
0
Рад, что смог помочь! ))
Я ж говорил — допиливал все под себя.
0
Все как часы пашет.
Еще раз спасибо=)
0
пробовали ли вы в хроме зайти в ленту?
Fatal error: Call to a member function getId()on a non-object in /home/mediciol/public_html/plugins/friendsfeed/classes/actions/ActionFeed.class.php on line 60
0
вот в хроме:
Fatal error: Call to a member function getId() on a non-object in /home/mediciol/public_html/plugins/friendsfeed/classes/actions/ActionFeed.class.php on line 60

В фоксе работает на ура, может в курсе в чем проблема?
0
это при заходе в саму ленту, все остальное работает
0
Дело не в броузере. Если ты не выполнил вход (логин), то такое сообщение будет отображаться, поскольку в строке 60 оно пытается получить ID твоего текущего пользователя.

Вот и получается, что в FF работает (где есть сессия), а в Хроме — нет.

Как вариант решения — прятать ссылку на ленту для анонимных пользователей или при переходе на ленту предлагать выполнить вход (перебрасывать на страницу логина).
0
Дело не в броузере. Если ты не выполнил вход (логин), то такое сообщение будет отображаться, поскольку в строке 60 оно пытается получить ID твоего текущего пользователя.

Вот и получается, что в FF работает (где есть сессия), а в Хроме — нет.

Как вариант решения — прятать ссылку на ленту для анонимных пользователей или при переходе на ленту предлагать выполнить вход (перебрасывать на страницу логина).

Например в этом же файле в функции Init вначале добавить такой код:

/**
* Проверяем авторизован ли юзер
*/
if (!$this->User_IsAuthorization()) {
	return Router::Action('login');
}
0
Конечно же это плюс!
0
А как сделать, что бы на всех страницах было «Лента друзей +2»
сейчас появляется только когда захожу на test.ru/friends/
0
а может кто-то выложить архивчиком уже доделаный под 0.4.2 плагин? спасибо)
0
  • avatar
  • romi
  • 15 февраля 2011, 23:59
Нужна помощь:
1) Адаптировать плагин по шаблон new
2) Чтобы ссылка на ленту друзей была видна из любой страницы
3) RSS ленты друзей — если это реально сделать
Готов заплатить
0
У вас ошибка в комментарии. Перед кодом plugin.xml название файла написано с большой буквы, когда должно быть с маленькой
0
  • avatar
  • cajoy
  • 08 сентября 2011, 10:38
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.