Хак: топ топиков из коллективных и персональных блогов отдельно
У меня в проекте коллективные и персональные блоги используются для разных целей, следовательно мне нужен был для них разный топ.
Вряд ли это кому-нибудь нужно, но выкладываю инструкцию, как можно повторить мою реализацию.
Расписываю все изменения подробно, чтобы всем было понятно, что за что отвечает :-)
Можно было по-быстрому поправить файлы шаблонов, я же предпочёл сделать всё более-менее чисто, дополнив ядро новыми функциями.
(тут я немного лукавлю — у себя в проектах я не дополнил движок функциями, а заменил своими старые :-) Вы можете поступить так же, тогда вы фактически не увеличите размер движка, а только дополните функциональность его core-функций. Делайте это, только если Вы действительно знаете, что делаете :-)
Итак, начнём.
Первым делом, добавляем в маппер core-модуля «topic» функцию, которая дублирует функционал core-функции «GetTopicsRatingByDate», а так же включает в себя возможность выборки по типам топиков. Последний аргумент ($Type) — массив с необходимыми типами топиков.
Теперь, добавляем в модуль «topic» функцию, которая дублирует функционал ф-ии «GetTopicsRatingByDate», только включает в себя возможность выборки по типу топиков (и при этом правильно работает с кэшем). Последний аргумент ($Type) — либо строка с 1м типом топика, либо массив с >=1 типов.
Редактируем экшн «Top». Регистрируем в нём 2 эвента: «personal» и «theme».
Добавляем функции эвентов:
Добавляем 2 шаблона для новых эвентов. Создаём 2 новых файла:
Содержимое theme.tpl
Содержимое personal.tpl
Редактируем шаблон меню. Тут уже всё по своему усмотрению.
Вот мой файл, где я убрал отображение топов блогов и смеси топиков, а вместо них поставил топы коллективных и персональных топиков отдельно:
Остались только языковые константы. Добавляем:
Всё.
Вряд ли это кому-нибудь нужно, но выкладываю инструкцию, как можно повторить мою реализацию.
Расписываю все изменения подробно, чтобы всем было понятно, что за что отвечает :-)
Можно было по-быстрому поправить файлы шаблонов, я же предпочёл сделать всё более-менее чисто, дополнив ядро новыми функциями.
(тут я немного лукавлю — у себя в проектах я не дополнил движок функциями, а заменил своими старые :-) Вы можете поступить так же, тогда вы фактически не увеличите размер движка, а только дополните функциональность его core-функций. Делайте это, только если Вы действительно знаете, что делаете :-)
Итак, начнём.
/classes/modules/topic/mapper/Topic.mapper.class.php
Первым делом, добавляем в маппер core-модуля «topic» функцию, которая дублирует функционал core-функции «GetTopicsRatingByDate», а так же включает в себя возможность выборки по типам топиков. Последний аргумент ($Type) — массив с необходимыми типами топиков.
public function GetTopicsRatingByDateType($sDate,$iLimit,$Type=array('personal','open')) {
$typestring="'".implode("','",$Type)."'"; //array=>string
$iCurrentUserId=-1;
if (is_object($this->oUserCurrent)) {
$iCurrentUserId=$this->oUserCurrent->getId();
}
/**
* оптимизирован
*/
$sql = "SELECT
t_fast.*,
tc.*,
u.user_login as user_login,
IF(tv.topic_id IS NULL,0,1) as user_is_vote,
tv.vote_delta as user_vote_delta,
IF(tqv.topic_id IS NULL,0,1) as user_question_is_vote,
IF(ft.topic_id IS NULL,0,1) as topic_is_favourite
FROM (
SELECT
t.*,
b.blog_title as blog_title,
b.blog_type as blog_type,
b.blog_url as blog_url
FROM
".DB_TABLE_TOPIC." as t,
".DB_TABLE_BLOG." as b
WHERE
t.topic_publish = 1
AND
t.topic_date_add >= ?
AND
t.topic_rating >= 0
AND
t.blog_id=b.blog_id
AND
b.blog_type in (".$typestring.")
ORDER by t.topic_rating desc, t.topic_id desc
LIMIT 0, ?d
) AS t_fast
JOIN ".DB_TABLE_USER." AS u ON t_fast.user_id=u.user_id
LEFT JOIN (
SELECT
topic_id,
vote_delta
FROM ".DB_TABLE_TOPIC_VOTE."
WHERE user_voter_id = ?d
) AS tv ON t_fast.topic_id=tv.topic_id
LEFT JOIN (
SELECT
topic_id
FROM ".DB_TABLE_FAVOURITE_TOPIC."
WHERE user_id = ?d
) AS ft ON t_fast.topic_id=ft.topic_id
LEFT JOIN (
SELECT
topic_id
FROM ".DB_TABLE_TOPIC_QUESTION_VOTE."
WHERE user_voter_id = ?d
) AS tqv ON t_fast.topic_id=tqv.topic_id
JOIN ".DB_TABLE_TOPIC_CONTENT." AS tc ON t_fast.topic_id=tc.topic_id
order by t_fast.topic_rating desc
";
$aTopics=array();
if ($aRows=$this->oDb->select($sql,$sDate,$iLimit,$iCurrentUserId,$iCurrentUserId,$iCurrentUserId)) {
foreach ($aRows as $aTopic) {
$aTopics[]=new TopicEntity_Topic($aTopic);
}
}
return $aTopics;
}
/classes/modules/topic/Topic.class.php
Теперь, добавляем в модуль «topic» функцию, которая дублирует функционал ф-ии «GetTopicsRatingByDate», только включает в себя возможность выборки по типу топиков (и при этом правильно работает с кэшем). Последний аргумент ($Type) — либо строка с 1м типом топика, либо массив с >=1 типов.
public function GetTopicsRatingByDateType($sDate,$iLimit=20,$Type=array('personal','open')) {
is_array($Type)?$typestring=implode('',sort($Type)):$Type=array($typestring=$Type); //new
$s2=-1;
if ($this->oUserCurrent) {
$s2=$this->oUserCurrent->getId();
}
if (false === ($data = $this->Cache_Get("topic_rating_{$typestring}_{$sDate}_{$s2}_{$iLimit}"))) {
$data = $this->oMapperTopic->GetTopicsRatingByDate($sDate,$iLimit,$Type);
$this->Cache_Set($data, "topic_rating_{$typestring}_{$sDate}_{$s2}_{$iLimit}", array('topic_update'), 60*5);
}
return $data;
}
/classes/actions/ActionTop.class.php
Редактируем экшн «Top». Регистрируем в нём 2 эвента: «personal» и «theme».
protected function RegisterEvent() {
$this->AddEvent('blog','EventBlog');
$this->AddEvent('topic','EventTopic');
$this->AddEvent('comment','EventComment');
$this->AddEvent('personal','EventPersonal'); // Только личные
$this->AddEvent('theme','EventTheme'); // Только тематические
}
Добавляем функции эвентов:
protected function EventPersonal() {
$this->sMenuSubItemSelect='personal';
$iTimeDelta=$this->GetTimeDelta();
$sDate=date("Y-m-d H:00:00",time()-$iTimeDelta);
$sType='personal'; // тип топиков
$aTopics=$this->Topic_GetTopicsRatingByDateType($sDate,20,$sType);
$this->Viewer_Assign('aTopics',$aTopics);
$this->Viewer_AddHtmlTitle('Топ топиков в личных блогах');
}
protected function EventTheme() {
$this->sMenuSubItemSelect='theme';
$iTimeDelta=$this->GetTimeDelta();
$sDate=date("Y-m-d H:00:00",time()-$iTimeDelta);
$sType='open'; // тип топиков
$aTopics=$this->Topic_GetTopicsRatingByDateType($sDate,20,$sType);
$this->Viewer_Assign('aTopics',$aTopics);
$this->Viewer_AddHtmlTitle('Топ топиков в тематических блогах');
}
Добавляем 2 шаблона для новых эвентов. Создаём 2 новых файла:
/templates/skin/new/actions/ActionTop/theme.tplи редактируем их содержимое. Это практически клоны файла «topic.tpl», лежащего в той же папке.
/templates/skin/new/actions/ActionTop/personal.tpl
Содержимое theme.tpl
{include file='header.tpl' menu="blog" }
<div class="topic top">
<h1>{$aLang.top_topics_theme}</h1>
<ul class="block-nav">
<li {if $aParams[0] and $aParams[0]=='24h'}class="active"{/if}><strong></strong><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/theme/24h/">{$aLang.blog_menu_top_period_24h}</a></li>
<li {if $aParams[0] and $aParams[0]=='7d'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/theme/7d/">{$aLang.blog_menu_top_period_7d}</a></li>
<li {if $aParams[0] and $aParams[0]=='30d'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/theme/30d/">{$aLang.blog_menu_top_period_30d}</a></li>
<li {if $aParams[0] and $aParams[0]=='all'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/theme/all/">{$aLang.blog_menu_top_period_all}</a><em></em></li>
</ul>
</div>
{include file='topic_list.tpl'}
{include file='footer.tpl'}
Содержимое personal.tpl
{include file='header.tpl' menu="blog" }
<div class="topic top">
<h1>{$aLang.top_topics_personal}</h1>
<ul class="block-nav">
<li {if $aParams[0] and $aParams[0]=='24h'}class="active"{/if}><strong></strong><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/personal/24h/">{$aLang.blog_menu_top_period_24h}</a></li>
<li {if $aParams[0] and $aParams[0]=='7d'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/personal/7d/">{$aLang.blog_menu_top_period_7d}</a></li>
<li {if $aParams[0] and $aParams[0]=='30d'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/personal/30d/">{$aLang.blog_menu_top_period_30d}</a></li>
<li {if $aParams[0] and $aParams[0]=='all'}class="active"{/if}><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/personal/all/">{$aLang.blog_menu_top_period_all}</a><em></em></li>
</ul>
</div>
{include file='topic_list.tpl'}
{include file='footer.tpl'}
/templates/skin/new/menu.blog.tpl
Редактируем шаблон меню. Тут уже всё по своему усмотрению.
Вот мой файл, где я убрал отображение топов блогов и смеси топиков, а вместо них поставил топы коллективных и персональных топиков отдельно:
<ul class="menu">
<li {if $sMenuItemSelect=='index'}class="active"{/if}>
<a href="{$DIR_WEB_ROOT}/">{$aLang.blog_menu_all}</a> {if $iCountTopicsNew>0}+{$iCountTopicsNew}{/if}
{if $sMenuItemSelect=='index'}
<ul class="sub-menu" >
<li {if $sMenuSubItemSelect=='good'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/">{$aLang.blog_menu_all_good}</a></div></li>
{if $iCountTopicsNew>0}<li {if $sMenuSubItemSelect=='new'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_NEW}/">{$aLang.blog_menu_all_new}</a> +{$iCountTopicsNew}</div></li>{/if}
</ul>
{/if}
</li>
<li {if $sMenuItemSelect=='blog'}class="active"{/if}>
<a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_BLOG}/">{$aLang.blog_menu_collective}</a> {if $iCountTopicsCollectiveNew>0}+{$iCountTopicsCollectiveNew}{/if}
{if $sMenuItemSelect=='blog'}
<ul class="sub-menu" >
<li {if $sMenuSubItemSelect=='good'}class="active"{/if}><div><a href="{$sMenuSubBlogUrl}">{$aLang.blog_menu_collective_good}</a></div></li>
{if $iCountTopicsBlogNew>0}<li {if $sMenuSubItemSelect=='new'}class="active"{/if}><div><a href="{$sMenuSubBlogUrl}new/">{$aLang.blog_menu_collective_new}</a> +{$iCountTopicsBlogNew}</div></li>{/if}
<li {if $sMenuSubItemSelect=='bad'}class="active"{/if}><div><a href="{$sMenuSubBlogUrl}bad/">{$aLang.blog_menu_collective_bad}</a></div></li>
</ul>
{/if}
</li>
<li {if $sMenuItemSelect=='log'}class="active"{/if}>
<a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_PERSONAL_BLOG}/">{$aLang.blog_menu_personal}</a> {if $iCountTopicsPersonalNew>0}+{$iCountTopicsPersonalNew}{/if}
{if $sMenuItemSelect=='log'}
<ul class="sub-menu" style="left: -50px;">
<li {if $sMenuSubItemSelect=='good'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_PERSONAL_BLOG}/">{$aLang.blog_menu_personal_good}</a></div></li>
{if $iCountTopicsPersonalNew>0}<li {if $sMenuSubItemSelect=='new'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_PERSONAL_BLOG}/new/">{$aLang.blog_menu_personal_new}</a> +{$iCountTopicsPersonalNew}</div></li>{/if}
<li {if $sMenuSubItemSelect=='bad'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_PERSONAL_BLOG}/bad/">{$aLang.blog_menu_personal_bad}</a></div></li>
</ul>
{/if}
</li>
<li {if $sMenuItemSelect=='top'}class="active"{/if}>
<a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/">{$aLang.blog_menu_top}</a>
{if $sMenuItemSelect=='top'}
<ul class="sub-menu" style="left: -80px;">
<!-- <li {if $sMenuSubItemSelect=='blog'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/blog/">{$aLang.blog_menu_top_blog}</a></div></li> -->
<!-- <li {if $sMenuSubItemSelect=='topic'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/topic/">{$aLang.blog_menu_top_topic}</a></div></li> -->
<li {if $sMenuSubItemSelect=='theme'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/theme/">{$aLang.blog_menu_collective}</a></div></li>
<li {if $sMenuSubItemSelect=='personal'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/personal/">{$aLang.blog_menu_personal}</a></div></li>
<li {if $sMenuSubItemSelect=='comment'}class="active"{/if}><div><a href="{$DIR_WEB_ROOT}/{$ROUTE_PAGE_TOP}/comment/">{$aLang.blog_menu_top_comment}</a></div></li>
</ul>
{/if}
</li>
</ul>
/templates/language/russian.php
Остались только языковые константы. Добавляем:
'top_topics_personal' => 'TOP личных топиков',
'top_topics_theme' => 'TOP тематических топиков',
Всё.
4 комментария
В каталог не добавлял, т.к. думал, что вряд ли хак будет пользоваться популярностью. Если это не так — добавим *)
На самом деле, хак актуален ровно до тех пор, пока разработчики не внесут в движок возможность сортировки выбранных топиков. Тогда можно будет всё это реализовать гораздо легче, без изменений в маппере.
В каталог обязательно нужно, пусть он лучше будет там лишним напоминанием разработчикам о необходимости реализации такой сортировки… Сам вобщем-то, проковырялся пол дня, пока не понял в чём прикол и не нашёл здесь Ваши посты :) Конечно вносить изменения в ядро не лучший путь, особенно для новичков, но всё-таки лучше так чем вобще никак… :)
Подскажите, пожалуйста, вроде делаю все как написано, но выводятся все равно и персональные и коллективные вместе.