ifhub.club/application/classes/modules/topic/Topic.class.php

2038 lines
78 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль для работы с топиками
*
* @package application.modules.topic
* @since 1.0
*/
class ModuleTopic extends Module
{
const TOPIC_TYPE_STATE_ACTIVE = 1;
const TOPIC_TYPE_STATE_NOT_ACTIVE = 0;
/**
* Объект маппера
*
* @var ModuleTopic_MapperTopic
*/
protected $oMapperTopic;
/**
* Объект текущего пользователя
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Список типов топика
*
* @var array
*/
protected $aTopicTypes = array();
/**
* Инициализация
*
*/
public function Init()
{
$this->oMapperTopic = Engine::GetMapper(__CLASS__);
$this->oUserCurrent = $this->User_GetUserCurrent();
$aTopicTypeItems = $this->GetTopicTypeItems(array('state' => self::TOPIC_TYPE_STATE_ACTIVE));
foreach ($aTopicTypeItems as $oTypeItem) {
$this->aTopicTypes[$oTypeItem->getCode()] = $oTypeItem;
}
}
/**
* Возвращает список типов топика, возвращаются только активные типы
*
* @param bool $bOnlyCode Вернуть только коды типов
*
* @return array
*/
public function GetTopicTypes($bOnlyCode = false)
{
return $bOnlyCode ? array_keys($this->aTopicTypes) : $this->aTopicTypes;
}
/**
* Возвращает объект типа топика, поиск только среди активных типов
*
* @param string $sType
*
* @return ModuleTopic_EntityTopicType|null
*/
public function GetTopicType($sType)
{
return isset($this->aTopicTypes[$sType]) ? $this->aTopicTypes[$sType] : null;
}
/**
* Возвращает первый доступные тип топика
*
* @return ModuleTopic_EntityTopicType|null
*/
public function GetTopicTypeFirst()
{
$oType = reset($this->aTopicTypes);
return $oType ?: null;
}
/**
* Проверяет разрешен ли данный тип топика
*
* @param string $sType Тип
* @return bool
*/
public function IsAllowTopicType($sType)
{
return array_key_exists($sType, $this->aTopicTypes);
}
/**
* Получает дополнительные данные(объекты) для топиков по их ID
*
* @param array $aTopicId Список ID топиков
* @param array|null $aAllowData Список типов дополнительных данных, которые нужно подключать к топикам
* @return array
*/
public function GetTopicsAdditionalData($aTopicId, $aAllowData = null)
{
if (is_null($aAllowData)) {
$aAllowData = array(
'user' => array(),
'blog' => array('owner' => array(), 'relation_user'),
'vote',
'favourite',
'comment_new',
'properties'
);
}
func_array_simpleflip($aAllowData);
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
/**
* Получаем "голые" топики
*/
$aTopics = $this->GetTopicsByArrayId($aTopicId);
/**
* Формируем ID дополнительных данных, которые нужно получить
*/
$aUserId = array();
$aBlogId = array();
foreach ($aTopics as $oTopic) {
if (isset($aAllowData['user'])) {
$aUserId[] = $oTopic->getUserId();
}
if (isset($aAllowData['blog'])) {
$aBlogId = array_merge($aBlogId, $oTopic->getBlogIds());
}
}
/**
* Получаем дополнительные данные
*/
$aTopicsVote = array();
$aFavouriteTopics = array();
$aTopicsRead = array();
$aUsers = isset($aAllowData['user']) && is_array($aAllowData['user']) ? $this->User_GetUsersAdditionalData($aUserId,
$aAllowData['user']) : $this->User_GetUsersAdditionalData($aUserId);
$aBlogs = isset($aAllowData['blog']) && is_array($aAllowData['blog']) ? $this->Blog_GetBlogsAdditionalData($aBlogId,
$aAllowData['blog']) : $this->Blog_GetBlogsAdditionalData($aBlogId);
if (isset($aAllowData['vote']) and $this->oUserCurrent) {
$aTopicsVote = $this->Vote_GetVoteByArray($aTopicId, 'topic', $this->oUserCurrent->getId());
}
if (isset($aAllowData['favourite']) and $this->oUserCurrent) {
$aFavouriteTopics = $this->GetFavouriteTopicsByArray($aTopicId, $this->oUserCurrent->getId());
}
if (isset($aAllowData['comment_new']) and $this->oUserCurrent) {
$aTopicsRead = $this->GetTopicsReadByArray($aTopicId, $this->oUserCurrent->getId());
}
/**
* Добавляем данные к результату - списку топиков
*/
foreach ($aTopics as $oTopic) {
if (isset($aUsers[$oTopic->getUserId()])) {
$oTopic->setUser($aUsers[$oTopic->getUserId()]);
} else {
$oTopic->setUser(null); // или $oTopic->setUser(new ModuleUser_EntityUser());
}
$aBlogsTopic = array();
foreach ($oTopic->getBlogIds() as $iBlogId) {
if (isset($aBlogs[$iBlogId])) {
$aBlogsTopic[] = $aBlogs[$iBlogId];
}
}
$oTopic->setBlogs($aBlogsTopic);
if (isset($aTopicsVote[$oTopic->getId()])) {
$oTopic->setVote($aTopicsVote[$oTopic->getId()]);
} else {
$oTopic->setVote(null);
}
if (isset($aFavouriteTopics[$oTopic->getId()])) {
$oTopic->setFavourite($aFavouriteTopics[$oTopic->getId()]);
} else {
$oTopic->setFavourite(null);
}
if (isset($aTopicsRead[$oTopic->getId()])) {
$oTopic->setCountCommentNew($oTopic->getCountComment() - $aTopicsRead[$oTopic->getId()]->getCommentCountLast());
$oTopic->setDateRead($aTopicsRead[$oTopic->getId()]->getDateRead());
} else {
$oTopic->setCountCommentNew(0);
$oTopic->setDateRead(date("Y-m-d H:i:s"));
}
}
/**
* Цепляем дополнительные поля
*/
if (isset($aAllowData['properties'])) {
$this->Property_RewriteGetItemsByFilter($aTopics, array('#properties' => true));
}
return $aTopics;
}
/**
* Добавляет топик
*
* @param ModuleTopic_EntityTopic $oTopic Объект топика
* @return ModuleTopic_EntityTopic|bool
*/
public function AddTopic(ModuleTopic_EntityTopic $oTopic)
{
if (!$oTopic->getDatePublish()) {
$oTopic->setDatePublish($oTopic->getDateAdd());
}
if ($sId = $this->oMapperTopic->AddTopic($oTopic)) {
$oTopic->setId($sId);
if ($oTopic->getPublish() and $oTopic->getTags()) {
$aTags = explode(',', $oTopic->getTags());
foreach ($aTags as $sTag) {
$oTag = Engine::GetEntity('Topic_TopicTag');
$oTag->setTopicId($oTopic->getId());
$oTag->setUserId($oTopic->getUserId());
$oTag->setBlogId($oTopic->getBlogId());
$oTag->setText($sTag);
$this->AddTopicTag($oTag);
}
}
/**
* Обновляем дополнительные поля
* Здесь важный момент - перед сохранением топика всегда нужно вызывать валидацию полей $this->Property_ValidateEntityPropertiesCheck($oTopic);
* т.к. она подготавливает данные полей для сохранений
* Валидация вызывается автоматически при вызове $oTopic->_Validate();
*/
$this->Property_UpdatePropertiesValue($oTopic->getPropertiesObject(), $oTopic);
//чистим зависимые кеши
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array(
'topic_new',
"topic_update_user_{$oTopic->getUserId()}",
"topic_new_blog_{$oTopic->getBlogId()}"
));
return $oTopic;
}
return false;
}
/**
* Добавление тега к топику
*
* @param ModuleTopic_EntityTopicTag $oTopicTag Объект тега топика
* @return int
*/
public function AddTopicTag(ModuleTopic_EntityTopicTag $oTopicTag)
{
return $this->oMapperTopic->AddTopicTag($oTopicTag);
}
/**
* Удаляет теги у топика
*
* @param int $sTopicId ID топика
* @return bool
*/
public function DeleteTopicTagsByTopicId($sTopicId)
{
return $this->oMapperTopic->DeleteTopicTagsByTopicId($sTopicId);
}
/**
* Удаляет топик.
* Если тип таблиц в БД InnoDB, то удалятся всё связи по топику(комменты,голосования,избранное)
*
* @param ModuleTopic_EntityTopic|int $oTopic Объект топика или ID
* @return bool
*/
public function DeleteTopic($oTopic)
{
if ($oTopic instanceof ModuleTopic_EntityTopic) {
$sTopicId = $oTopic->getId();
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("topic_update_user_{$oTopic->getUserId()}"));
} else {
$sTopicId = $oTopic;
$oTopic = $this->GetTopicById($sTopicId);
}
/**
* Удаляем дополнительные поля
*/
$this->Property_RemovePropertiesValue($oTopic);
/**
* Чистим зависимые кеши
*/
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('topic_update'));
$this->Cache_Delete("topic_{$sTopicId}");
/**
* Если топик успешно удален, удаляем связанные данные
*/
if ($this->oMapperTopic->DeleteTopic($sTopicId)) {
/**
* Обновляем счетчики топиков в блогах
*/
$this->Blog_RecalculateCountTopicByBlogId($oTopic->getBlogsId());
return $this->DeleteTopicAdditionalData($sTopicId);
}
return false;
}
/**
* Удаляет свзяанные с топика данные
*
* @param int $iTopicId ID топика
* @return bool
*/
public function DeleteTopicAdditionalData($iTopicId)
{
/**
* Чистим зависимые кеши
*/
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('topic_update'));
$this->Cache_Delete("topic_{$iTopicId}");
/**
* Удаляем контент топика
*/
$this->DeleteTopicContentByTopicId($iTopicId);
/**
* Удаляем медиа данные топика
*/
$this->Media_RemoveTarget('topic', $iTopicId, true);
/**
* Удаляем комментарии к топику.
* При удалении комментариев они удаляются из избранного,прямого эфира и голоса за них
*/
$this->Comment_DeleteCommentByTargetId($iTopicId, 'topic');
/**
* Удаляем топик из избранного
*/
$this->DeleteFavouriteTopicByArrayId($iTopicId);
/**
* Удаляем топик из прочитанного
*/
$this->DeleteTopicReadByArrayId($iTopicId);
/**
* Удаляем голосование к топику
*/
$this->Vote_DeleteVoteByTarget($iTopicId, 'topic');
/**
* Удаляем теги
*/
$this->DeleteTopicTagsByTopicId($iTopicId);
return true;
}
/**
* Обновляет топик
*
* @param ModuleTopic_EntityTopic $oTopic Объект топика
* @return bool
*/
public function UpdateTopic(ModuleTopic_EntityTopic $oTopic)
{
/**
* Получаем топик ДО изменения
*/
$oTopicOld = $this->GetTopicById($oTopic->getId());
$oTopic->setDateEdit(date("Y-m-d H:i:s"));
if ($this->oMapperTopic->UpdateTopic($oTopic)) {
/**
* Если топик изменил видимость(publish) или локацию (BlogId) или список тегов
*/
if (($oTopic->getPublish() != $oTopicOld->getPublish()) || ($oTopic->getBlogId() != $oTopicOld->getBlogId()) || ($oTopic->getTags() != $oTopicOld->getTags())) {
/**
* Обновляем теги
*/
$this->DeleteTopicTagsByTopicId($oTopic->getId());
if ($oTopic->getPublish() and $oTopic->getTags()) {
$aTags = explode(',', $oTopic->getTags());
foreach ($aTags as $sTag) {
$oTag = Engine::GetEntity('Topic_TopicTag');
$oTag->setTopicId($oTopic->getId());
$oTag->setUserId($oTopic->getUserId());
$oTag->setBlogId($oTopic->getBlogId());
$oTag->setText($sTag);
$this->AddTopicTag($oTag);
}
}
}
if ($oTopic->getPublish() != $oTopicOld->getPublish()) {
/**
* Обновляем избранное
*/
$this->SetFavouriteTopicPublish($oTopic->getId(), $oTopic->getPublish());
/**
* Удаляем комментарий топика из прямого эфира
*/
if ($oTopic->getPublish() == 0) {
$this->Comment_DeleteCommentOnlineByTargetId($oTopic->getId(), 'topic');
}
/**
* Изменяем видимость комментов
*/
$this->Comment_SetCommentsPublish($oTopic->getId(), 'topic', $oTopic->getPublish());
}
/**
* Смена главного блога
*/
if ($oTopic->getBlogId() != $oTopicOld->getBlogId()) {
// меняем target parent у комментов
$this->Comment_MoveTargetParent($oTopicOld->getBlogId(), 'topic', $oTopic->getBlogId());
// меняем target parent у комментов в прямом эфире
$this->Comment_MoveTargetParentOnline($oTopicOld->getBlogId(), 'topic', $oTopic->getBlogId());
}
/**
* Обновляем дополнительные поля
* Здесь важный момент - перед сохранением топика всегда нужно вызывать валидацию полей $this->Property_ValidateEntityPropertiesCheck($oTopic);
* т.к. она подготавливает данные полей для сохранений
* Валидация вызывается автоматически при вызове $oTopic->_Validate();
*/
$this->Property_UpdatePropertiesValue($oTopic->getPropertiesObject(), $oTopic);
//чистим зависимые кеши
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array('topic_update', "topic_update_user_{$oTopic->getUserId()}"));
$this->Cache_Delete("topic_{$oTopic->getId()}");
return true;
}
return false;
}
/**
* Обновляет контент топика в БД (таблица topic_content)
*
* @param ModuleTopic_EntityTopic $oTopic
*
* @return bool
*/
public function UpdateTopicContent($oTopic)
{
$bRes = $this->oMapperTopic->UpdateTopicContent($oTopic);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array('topic_update', "topic_update_user_{$oTopic->getUserId()}"));
$this->Cache_Delete("topic_{$oTopic->getId()}");
return $bRes;
}
/**
* Удаление контента топика по его номеру
*
* @param int $iTopicId ID топика
* @return bool
*/
public function DeleteTopicContentByTopicId($iTopicId)
{
return $this->oMapperTopic->DeleteTopicContentByTopicId($iTopicId);
}
/**
* Получить топик по айдишнику
*
* @param int $sId ID топика
* @return ModuleTopic_EntityTopic|null
*/
public function GetTopicById($sId)
{
if (!is_numeric($sId)) {
return null;
}
$aTopics = $this->GetTopicsAdditionalData($sId);
if (isset($aTopics[$sId])) {
return $aTopics[$sId];
}
return null;
}
/**
* Получить топик по url/slug
*
* @param string $sSlug url/slug топика
* @return ModuleTopic_EntityTopic|null
*/
public function GetTopicBySlug($sSlug)
{
if (!is_scalar($sSlug)) {
return null;
}
$aTopics = $this->GetTopicsByFilter(array('topic_slug' => $sSlug), 1, 1);
if ($aTopics['collection']) {
return reset($aTopics['collection']);
}
return null;
}
/**
* Получить список топиков по списку айдишников
*
* @param array $aTopicId Список ID топиков
* @return array
*/
public function GetTopicsByArrayId($aTopicId)
{
if (!$aTopicId) {
return array();
}
if (Config::Get('sys.cache.solid')) {
return $this->GetTopicsByArrayIdSolid($aTopicId);
}
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
$aTopicId = array_unique($aTopicId);
$aTopics = array();
$aTopicIdNotNeedQuery = array();
/**
* Делаем мульти-запрос к кешу
*/
$aCacheKeys = func_build_cache_keys($aTopicId, 'topic_');
if (false !== ($data = $this->Cache_Get($aCacheKeys))) {
/**
* проверяем что досталось из кеша
*/
foreach ($aCacheKeys as $sValue => $sKey) {
if (array_key_exists($sKey, $data)) {
if ($data[$sKey]) {
$aTopics[$data[$sKey]->getId()] = $data[$sKey];
} else {
$aTopicIdNotNeedQuery[] = $sValue;
}
}
}
}
/**
* Смотрим каких топиков не было в кеше и делаем запрос в БД
*/
$aTopicIdNeedQuery = array_diff($aTopicId, array_keys($aTopics));
$aTopicIdNeedQuery = array_diff($aTopicIdNeedQuery, $aTopicIdNotNeedQuery);
$aTopicIdNeedStore = $aTopicIdNeedQuery;
if ($data = $this->oMapperTopic->GetTopicsByArrayId($aTopicIdNeedQuery)) {
foreach ($data as $oTopic) {
/**
* Добавляем к результату и сохраняем в кеш
*/
$aTopics[$oTopic->getId()] = $oTopic;
$this->Cache_Set($oTopic, "topic_{$oTopic->getId()}", array(), 60 * 60 * 24 * 4);
$aTopicIdNeedStore = array_diff($aTopicIdNeedStore, array($oTopic->getId()));
}
}
/**
* Сохраняем в кеш запросы не вернувшие результата
*/
foreach ($aTopicIdNeedStore as $sId) {
$this->Cache_Set(null, "topic_{$sId}", array(), 60 * 60 * 24 * 4);
}
/**
* Сортируем результат согласно входящему массиву
*/
$aTopics = func_array_sort_by_keys($aTopics, $aTopicId);
return $aTopics;
}
/**
* Получить список топиков по списку айдишников, но используя единый кеш
*
* @param array $aTopicId Список ID топиков
* @return array
*/
public function GetTopicsByArrayIdSolid($aTopicId)
{
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
$aTopicId = array_unique($aTopicId);
$aTopics = array();
$s = join(',', $aTopicId);
if (false === ($data = $this->Cache_Get("topic_id_{$s}"))) {
$data = $this->oMapperTopic->GetTopicsByArrayId($aTopicId);
foreach ($data as $oTopic) {
$aTopics[$oTopic->getId()] = $oTopic;
}
$this->Cache_Set($aTopics, "topic_id_{$s}", array("topic_update"), 60 * 60 * 24 * 1);
return $aTopics;
}
return $data;
}
/**
* Получает список топиков из избранного
*
* @param int $sUserId ID пользователя
* @param int $iCurrPage Номер текущей страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetTopicsFavouriteByUserId($sUserId, $iCurrPage, $iPerPage)
{
$aCloseTopics = array();
/**
* Получаем список идентификаторов избранных записей
*/
$data = ($this->oUserCurrent && $sUserId == $this->oUserCurrent->getId())
? $this->Favourite_GetFavouritesByUserId($sUserId, 'topic', $iCurrPage, $iPerPage, $aCloseTopics)
: $this->Favourite_GetFavouriteOpenTopicsByUserId($sUserId, $iCurrPage, $iPerPage);
/**
* Получаем записи по переданому массиву айдишников
*/
$data['collection'] = $this->GetTopicsAdditionalData($data['collection']);
return $data;
}
/**
* Возвращает число топиков в избранном
*
* @param int $sUserId ID пользователя
* @return int
*/
public function GetCountTopicsFavouriteByUserId($sUserId)
{
$aCloseTopics = array();
return ($this->oUserCurrent && $sUserId == $this->oUserCurrent->getId())
? $this->Favourite_GetCountFavouritesByUserId($sUserId, 'topic', $aCloseTopics)
: $this->Favourite_GetCountFavouriteOpenTopicsByUserId($sUserId);
}
/**
* Список топиков по фильтру
*
* @param array $aFilter Фильтр
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param array|null $aAllowData Список типов данных для подгрузки в топики
* @return array('collection'=>array,'count'=>int)
*/
public function GetTopicsByFilter($aFilter, $iPage = 1, $iPerPage = 10, $aAllowData = null)
{
if (!is_numeric($iPage) or $iPage <= 0) {
$iPage = 1;
}
$s = serialize($aFilter);
if (false === ($data = $this->Cache_Get("topic_filter_{$s}_{$iPage}_{$iPerPage}"))) {
$data = array(
'collection' => $this->oMapperTopic->GetTopics($aFilter, $iCount, $iPage, $iPerPage),
'count' => $iCount
);
$this->Cache_Set($data, "topic_filter_{$s}_{$iPage}_{$iPerPage}", array('topic_update', 'topic_new'),
60 * 60 * 24 * 3);
}
$data['collection'] = $this->GetTopicsAdditionalData($data['collection'], $aAllowData);
return $data;
}
/**
* Количество топиков по фильтру
*
* @param array $aFilter Фильтр
* @return int
*/
public function GetCountTopicsByFilter($aFilter)
{
$s = serialize($aFilter);
if (false === ($data = $this->Cache_Get("topic_count_{$s}"))) {
$data = $this->oMapperTopic->GetCountTopics($aFilter);
$this->Cache_Set($data, "topic_count_{$s}", array('topic_update', 'topic_new'), 60 * 60 * 24 * 1);
}
return $data;
}
/**
* Количество черновиков у пользователя
*
* @param int $iUserId ID пользователя
* @return int
*/
public function GetCountDraftTopicsByUserId($iUserId)
{
return $this->GetCountTopicsByFilter(array(
'user_id' => $iUserId,
'topic_publish' => 0
));
}
/**
* Получает список хороших топиков для вывода на главную страницу(из всех блогов, как коллективных так и персональных)
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsGood($iPage, $iPerPage, $bAddAccessible = true)
{
$aFilter = array(
'blog_type' => array(
'personal',
'open'
),
'topic_publish' => 1,
'topic_rating' => array(
'value' => Config::Get('module.blog.index_good'),
'type' => 'top',
'publish_index' => 1,
)
);
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $bAddAccessible) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает список новых топиков, ограничение новизны по дате из конфига
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsNew($iPage, $iPerPage, $bAddAccessible = true)
{
$sDate = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
$aFilter = array(
'blog_type' => array(
'personal',
'open',
),
'topic_publish' => 1,
'topic_new' => $sDate,
);
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $bAddAccessible) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает список ВСЕХ новых топиков
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsNewAll($iPage, $iPerPage, $bAddAccessible = true)
{
$aFilter = array(
'blog_type' => array(
'personal',
'open',
),
'topic_publish' => 1,
);
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $bAddAccessible) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает список ВСЕХ обсуждаемых топиков
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param int|string $sPeriod Период в виде секунд или конкретной даты
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsDiscussed($iPage, $iPerPage, $sPeriod = null, $bAddAccessible = true)
{
if (is_numeric($sPeriod)) {
// количество последних секунд
$sPeriod = date("Y-m-d H:00:00", time() - $sPeriod);
}
$aFilter = array(
'blog_type' => array(
'personal',
'open',
),
'topic_publish' => 1
);
if ($sPeriod) {
$aFilter['topic_date_more'] = $sPeriod;
}
$aFilter['order'] = ' t.topic_count_comment desc, t.topic_id desc ';
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $bAddAccessible) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает список ВСЕХ рейтинговых топиков
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param int|string $sPeriod Период в виде секунд или конкретной даты
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsTop($iPage, $iPerPage, $sPeriod = null, $bAddAccessible = true)
{
if (is_numeric($sPeriod)) {
// количество последних секунд
$sPeriod = date("Y-m-d H:00:00", time() - $sPeriod);
}
$aFilter = array(
'blog_type' => array(
'personal',
'open',
),
'topic_publish' => 1
);
if ($sPeriod) {
$aFilter['topic_date_more'] = $sPeriod;
}
$aFilter['order'] = array('t.topic_rating desc', 't.topic_id desc');
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $bAddAccessible) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает заданое число последних топиков
*
* @param int $iCount Количество
* @return array
*/
public function GetTopicsLast($iCount)
{
$aFilter = array(
'blog_type' => array(
'personal',
'open',
),
'topic_publish' => 1,
);
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => 1, 'iPerPage' => $iCount, 'sMethod' => __FUNCTION__));
$aReturn = $this->GetTopicsByFilter($aFilter, 1, $iCount);
if (isset($aReturn['collection'])) {
return $aReturn['collection'];
}
return false;
}
/**
* список топиков из персональных блогов
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param string $sShowType Тип выборки топиков
* @param string|int $sPeriod Период в виде секунд или конкретной даты
* @return array
*/
public function GetTopicsPersonal($iPage, $iPerPage, $sShowType = 'good', $sPeriod = null)
{
if (is_numeric($sPeriod)) {
// количество последних секунд
$sPeriod = date("Y-m-d H:00:00", time() - $sPeriod);
}
$aFilter = array(
'blog_type' => array(
'personal',
),
'topic_publish' => 1,
);
if ($sPeriod) {
$aFilter['topic_date_more'] = $sPeriod;
}
switch ($sShowType) {
case 'good':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.personal_good'),
'type' => 'top',
);
break;
case 'bad':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.personal_good'),
'type' => 'down',
);
break;
case 'new':
$aFilter['topic_new'] = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
break;
case 'newall':
// нет доп фильтра
break;
case 'discussed':
$aFilter['order'] = array('t.topic_count_comment desc', 't.topic_id desc');
break;
case 'top':
$aFilter['order'] = array('t.topic_rating desc', 't.topic_id desc');
break;
default:
break;
}
$this->Hook_Run('get_topics_by_custom_filter',
array(
'aFilter' => &$aFilter,
'iPage' => $iPage,
'iPerPage' => $iPerPage,
'sShowType' => $sShowType,
'sMethod' => __FUNCTION__
));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает число новых топиков в персональных блогах
*
* @return int
*/
public function GetCountTopicsPersonalNew()
{
$sDate = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
$aFilter = array(
'blog_type' => array(
'personal',
),
'topic_publish' => 1,
'topic_new' => $sDate,
);
return $this->GetCountTopicsByFilter($aFilter);
}
/**
* Получает список топиков по юзеру
*
* @param int $sUserId ID пользователя
* @param int $iPublish Флаг публикации топика
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetTopicsPersonalByUser($sUserId, $iPublish, $iPage, $iPerPage)
{
$aFilter = array(
'topic_publish' => $iPublish,
'user_id' => $sUserId,
'blog_type' => array('open', 'personal'),
);
/**
* Если пользователь смотрит свой профиль, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $this->oUserCurrent->getId() == $sUserId) {
$aFilter['blog_type'][] = 'close';
}
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Возвращает количество топиков которые создал юзер
*
* @param int $sUserId ID пользователя
* @param int $iPublish Флаг публикации топика
* @return array
*/
public function GetCountTopicsPersonalByUser($sUserId, $iPublish)
{
$aFilter = array(
'topic_publish' => $iPublish,
'user_id' => $sUserId,
'blog_type' => array('open', 'personal'),
);
/**
* Если пользователь смотрит свой профиль, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent && $this->oUserCurrent->getId() == $sUserId) {
$aFilter['blog_type'][] = 'close';
}
$s = serialize($aFilter);
if (false === ($data = $this->Cache_Get("topic_count_user_{$s}"))) {
$data = $this->oMapperTopic->GetCountTopics($aFilter);
$this->Cache_Set($data, "topic_count_user_{$s}", array("topic_update_user_{$sUserId}"), 60 * 60 * 24);
}
return $data;
}
/**
* Получает список топиков из указанного блога
*
* @param int $iBlogId ID блога
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param array $aAllowData Список типов данных для подгрузки в топики
* @param bool $bIdsOnly Возвращать только ID или список объектов
* @return array
*/
public function GetTopicsByBlogId($iBlogId, $iPage = 1, $iPerPage = 20, $aAllowData = array(), $bIdsOnly = true)
{
$aFilter = array('blog_id' => $iBlogId);
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => $iPage, 'iPerPage' => $iPerPage, 'sMethod' => __FUNCTION__));
if (!$aTopics = $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage, $aAllowData)) {
return array();
}
return ($bIdsOnly)
? array_keys($aTopics['collection'])
: $aTopics;
}
/**
* Список топиков из коллективных блогов
*
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param string $sShowType Тип выборки топиков
* @param string $sPeriod Период в виде секунд или конкретной даты
* @return array
*/
public function GetTopicsCollective($iPage, $iPerPage, $sShowType = 'good', $sPeriod = null)
{
if (is_numeric($sPeriod)) {
// количество последних секунд
$sPeriod = date("Y-m-d H:00:00", time() - $sPeriod);
}
$aFilter = array(
'blog_type' => array(
'open',
),
'topic_publish' => 1,
);
if ($sPeriod) {
$aFilter['topic_date_more'] = $sPeriod;
}
switch ($sShowType) {
case 'good':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.collective_good'),
'type' => 'top',
);
break;
case 'bad':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.collective_good'),
'type' => 'down',
);
break;
case 'new':
$aFilter['topic_new'] = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
break;
case 'newall':
// нет доп фильтра
break;
case 'discussed':
$aFilter['order'] = array('t.topic_count_comment desc', 't.topic_id desc');
break;
case 'top':
$aFilter['order'] = array('t.topic_rating desc', 't.topic_id desc');
break;
default:
break;
}
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
$this->Hook_Run('get_topics_by_custom_filter',
array(
'aFilter' => &$aFilter,
'iPage' => $iPage,
'iPerPage' => $iPerPage,
'sShowType' => $sShowType,
'sMethod' => __FUNCTION__
));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает число новых топиков в коллективных блогах
*
* @return int
*/
public function GetCountTopicsCollectiveNew()
{
$sDate = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
$aFilter = array(
'blog_type' => array(
'open',
),
'topic_publish' => 1,
'topic_new' => $sDate,
);
/**
* Если пользователь авторизирован, то добавляем в выдачу
* закрытые блоги в которых он состоит
*/
if ($this->oUserCurrent) {
$aOpenBlogs = $this->Blog_GetAccessibleBlogsByUser($this->oUserCurrent);
if (count($aOpenBlogs)) {
$aFilter['blog_type']['close'] = $aOpenBlogs;
}
}
return $this->GetCountTopicsByFilter($aFilter);
}
/**
* Получает топики по рейтингу и дате
*
* @param string $sDate Дата
* @param int $iLimit Количество
* @return array
*/
public function GetTopicsRatingByDate($sDate, $iLimit = 20)
{
/**
* Получаем список блогов, топики которых нужно исключить из выдачи
*/
$aCloseBlogs = ($this->oUserCurrent)
? $this->Blog_GetInaccessibleBlogsByUser($this->oUserCurrent)
: $this->Blog_GetInaccessibleBlogsByUser();
$s = serialize($aCloseBlogs);
if (false === ($data = $this->Cache_Get("topic_rating_{$sDate}_{$iLimit}_{$s}"))) {
$data = $this->oMapperTopic->GetTopicsRatingByDate($sDate, $iLimit, $aCloseBlogs);
$this->Cache_Set($data, "topic_rating_{$sDate}_{$iLimit}_{$s}", array('topic_update'), 60 * 60 * 24 * 2);
}
$data = $this->GetTopicsAdditionalData($data);
return $data;
}
/**
* Список топиков из блога
*
* @param ModuleBlog_EntityBlog $oBlog Объект блога
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param string $sShowType Тип выборки топиков
* @param string $sPeriod Период в виде секунд или конкретной даты
* @return array
*/
public function GetTopicsByBlog($oBlog, $iPage, $iPerPage, $sShowType = 'good', $sPeriod = null)
{
if (is_numeric($sPeriod)) {
// количество последних секунд
$sPeriod = date("Y-m-d H:00:00", time() - $sPeriod);
}
$aFilter = array(
'topic_publish' => 1,
'blog_id' => $oBlog->getId(),
);
if ($sPeriod) {
$aFilter['topic_date_more'] = $sPeriod;
}
switch ($sShowType) {
case 'good':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.collective_good'),
'type' => 'top',
);
break;
case 'bad':
$aFilter['topic_rating'] = array(
'value' => Config::Get('module.blog.collective_good'),
'type' => 'down',
);
break;
case 'new':
$aFilter['topic_new'] = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
break;
case 'newall':
// нет доп фильтра
break;
case 'discussed':
$aFilter['order'] = array('t.topic_count_comment desc', 't.topic_id desc');
break;
case 'top':
$aFilter['order'] = array('t.topic_rating desc', 't.topic_id desc');
break;
default:
break;
}
$this->Hook_Run('get_topics_by_custom_filter',
array(
'aFilter' => &$aFilter,
'iPage' => $iPage,
'iPerPage' => $iPerPage,
'sShowType' => $sShowType,
'sMethod' => __FUNCTION__
));
return $this->GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}
/**
* Получает число новых топиков из блога
*
* @param ModuleBlog_EntityBlog $oBlog Объект блога
* @return int
*/
public function GetCountTopicsByBlogNew($oBlog)
{
$sDate = date("Y-m-d H:00:00", time() - Config::Get('module.topic.new_time'));
$aFilter = array(
'topic_publish' => 1,
'blog_id' => $oBlog->getId(),
'topic_new' => $sDate,
);
return $this->GetCountTopicsByFilter($aFilter);
}
/**
* Получает список топиков по тегу
*
* @param string $sTag Тег
* @param int $iPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param bool $bAddAccessible Указывает на необходимость добавить в выдачу топики,
* из блогов доступных пользователю. При указании false,
* в выдачу будут переданы только топики из общедоступных блогов.
* @return array
*/
public function GetTopicsByTag($sTag, $iPage, $iPerPage, $bAddAccessible = true)
{
$aCloseBlogs = ($this->oUserCurrent && $bAddAccessible)
? $this->Blog_GetInaccessibleBlogsByUser($this->oUserCurrent)
: $this->Blog_GetInaccessibleBlogsByUser();
$s = serialize($aCloseBlogs);
if (false === ($data = $this->Cache_Get("topic_tag_{$sTag}_{$iPage}_{$iPerPage}_{$s}"))) {
$data = array(
'collection' => $this->oMapperTopic->GetTopicsByTag($sTag, $aCloseBlogs, $iCount, $iPage, $iPerPage),
'count' => $iCount
);
$this->Cache_Set($data, "topic_tag_{$sTag}_{$iPage}_{$iPerPage}_{$s}", array('topic_update', 'topic_new'),
60 * 60 * 24 * 2);
}
$data['collection'] = $this->GetTopicsAdditionalData($data['collection']);
return $data;
}
/**
* Получает список тегов топиков
*
* @param int $iLimit Количество
* @param array $aExcludeTopic Список ID топиков для исключения
* @return array
*/
public function GetTopicTags($iLimit, $aExcludeTopic = array())
{
$s = serialize($aExcludeTopic);
if (false === ($data = $this->Cache_Get("tag_{$iLimit}_{$s}"))) {
$data = $this->oMapperTopic->GetTopicTags($iLimit, $aExcludeTopic);
$this->Cache_Set($data, "tag_{$iLimit}_{$s}", array('topic_update', 'topic_new'), 60 * 60 * 24 * 3);
}
return $data;
}
/**
* Получает список тегов из топиков открытых блогов (open,personal)
*
* @param int $iLimit Количество
* @param int|null $iUserId ID пользователя, чью теги получаем
* @return array
*/
public function GetOpenTopicTags($iLimit, $iUserId = null)
{
if (false === ($data = $this->Cache_Get("tag_{$iLimit}_{$iUserId}_open"))) {
$data = $this->oMapperTopic->GetOpenTopicTags($iLimit, $iUserId);
$this->Cache_Set($data, "tag_{$iLimit}_{$iUserId}_open", array('topic_update', 'topic_new'),
60 * 60 * 24 * 3);
}
return $data;
}
/**
* Увеличивает у топика число комментов
*
* @param int $sTopicId ID топика
* @return bool
*/
public function increaseTopicCountComment($sTopicId)
{
$this->Cache_Delete("topic_{$sTopicId}");
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array("topic_update"));
return $this->oMapperTopic->increaseTopicCountComment($sTopicId);
}
/**
* Получает привязку топика к ибранному(добавлен ли топик в избранное у юзера)
*
* @param int $sTopicId ID топика
* @param int $sUserId ID пользователя
* @return ModuleFavourite_EntityFavourite
*/
public function GetFavouriteTopic($sTopicId, $sUserId)
{
return $this->Favourite_GetFavourite($sTopicId, 'topic', $sUserId);
}
/**
* Получить список избранного по списку айдишников
*
* @param array $aTopicId Список ID топиков
* @param int $sUserId ID пользователя
* @return array
*/
public function GetFavouriteTopicsByArray($aTopicId, $sUserId)
{
return $this->Favourite_GetFavouritesByArray($aTopicId, 'topic', $sUserId);
}
/**
* Получить список избранного по списку айдишников, но используя единый кеш
*
* @param array $aTopicId Список ID топиков
* @param int $sUserId ID пользователя
* @return array
*/
public function GetFavouriteTopicsByArraySolid($aTopicId, $sUserId)
{
return $this->Favourite_GetFavouritesByArraySolid($aTopicId, 'topic', $sUserId);
}
/**
* Добавляет топик в избранное
*
* @param ModuleFavourite_EntityFavourite $oFavouriteTopic Объект избранного
* @return bool
*/
public function AddFavouriteTopic(ModuleFavourite_EntityFavourite $oFavouriteTopic)
{
return $this->Favourite_AddFavourite($oFavouriteTopic);
}
/**
* Удаляет топик из избранного
*
* @param ModuleFavourite_EntityFavourite $oFavouriteTopic Объект избранного
* @return bool
*/
public function DeleteFavouriteTopic(ModuleFavourite_EntityFavourite $oFavouriteTopic)
{
return $this->Favourite_DeleteFavourite($oFavouriteTopic);
}
/**
* Устанавливает переданный параметр публикации таргета (топика)
*
* @param int $sTopicId ID топика
* @param int $iPublish Флаг публикации топика
* @return bool
*/
public function SetFavouriteTopicPublish($sTopicId, $iPublish)
{
return $this->Favourite_SetFavouriteTargetPublish($sTopicId, 'topic', $iPublish);
}
/**
* Удаляет топики из избранного по списку
*
* @param array $aTopicId Список ID топиков
* @return bool
*/
public function DeleteFavouriteTopicByArrayId($aTopicId)
{
return $this->Favourite_DeleteFavouriteByTargetId($aTopicId, 'topic');
}
/**
* Получает список тегов по первым буквам тега
*
* @param string $sTag Тэг
* @param int $iLimit Количество
* @return bool
*/
public function GetTopicTagsByLike($sTag, $iLimit)
{
if (false === ($data = $this->Cache_Get("tag_like_{$sTag}_{$iLimit}"))) {
$data = $this->oMapperTopic->GetTopicTagsByLike($sTag, $iLimit);
$this->Cache_Set($data, "tag_like_{$sTag}_{$iLimit}", array("topic_update", "topic_new"), 60 * 60 * 24 * 3);
}
return $data;
}
/**
* Обновляем/устанавливаем дату прочтения топика, если читаем его первый раз то добавляем
*
* @param ModuleTopic_EntityTopicRead $oTopicRead Объект факта чтения топика
* @return bool
*/
public function SetTopicRead(ModuleTopic_EntityTopicRead $oTopicRead)
{
if ($this->GetTopicRead($oTopicRead->getTopicId(), $oTopicRead->getUserId())) {
$this->Cache_Delete("topic_read_{$oTopicRead->getTopicId()}_{$oTopicRead->getUserId()}");
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("topic_read_user_{$oTopicRead->getUserId()}"));
$this->oMapperTopic->UpdateTopicRead($oTopicRead);
} else {
$this->Cache_Delete("topic_read_{$oTopicRead->getTopicId()}_{$oTopicRead->getUserId()}");
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("topic_read_user_{$oTopicRead->getUserId()}"));
$this->oMapperTopic->AddTopicRead($oTopicRead);
}
return true;
}
/**
* Получаем дату прочтения топика юзером
*
* @param int $sTopicId ID топика
* @param int $sUserId ID пользователя
* @return ModuleTopic_EntityTopicRead|null
*/
public function GetTopicRead($sTopicId, $sUserId)
{
$data = $this->GetTopicsReadByArray($sTopicId, $sUserId);
if (isset($data[$sTopicId])) {
return $data[$sTopicId];
}
return null;
}
/**
* Удаляет записи о чтении записей по списку идентификаторов
*
* @param array|int $aTopicId Список ID топиков
* @return bool
*/
public function DeleteTopicReadByArrayId($aTopicId)
{
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
return $this->oMapperTopic->DeleteTopicReadByArrayId($aTopicId);
}
/**
* Получить список просмотром/чтения топиков по списку айдишников
*
* @param array $aTopicId Список ID топиков
* @param int $sUserId ID пользователя
* @return array
*/
public function GetTopicsReadByArray($aTopicId, $sUserId)
{
if (!$aTopicId) {
return array();
}
if (Config::Get('sys.cache.solid')) {
return $this->GetTopicsReadByArraySolid($aTopicId, $sUserId);
}
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
$aTopicId = array_unique($aTopicId);
$aTopicsRead = array();
$aTopicIdNotNeedQuery = array();
/**
* Делаем мульти-запрос к кешу
*/
$aCacheKeys = func_build_cache_keys($aTopicId, 'topic_read_', '_' . $sUserId);
if (false !== ($data = $this->Cache_Get($aCacheKeys))) {
/**
* проверяем что досталось из кеша
*/
foreach ($aCacheKeys as $sValue => $sKey) {
if (array_key_exists($sKey, $data)) {
if ($data[$sKey]) {
$aTopicsRead[$data[$sKey]->getTopicId()] = $data[$sKey];
} else {
$aTopicIdNotNeedQuery[] = $sValue;
}
}
}
}
/**
* Смотрим каких топиков не было в кеше и делаем запрос в БД
*/
$aTopicIdNeedQuery = array_diff($aTopicId, array_keys($aTopicsRead));
$aTopicIdNeedQuery = array_diff($aTopicIdNeedQuery, $aTopicIdNotNeedQuery);
$aTopicIdNeedStore = $aTopicIdNeedQuery;
if ($data = $this->oMapperTopic->GetTopicsReadByArray($aTopicIdNeedQuery, $sUserId)) {
foreach ($data as $oTopicRead) {
/**
* Добавляем к результату и сохраняем в кеш
*/
$aTopicsRead[$oTopicRead->getTopicId()] = $oTopicRead;
$this->Cache_Set($oTopicRead, "topic_read_{$oTopicRead->getTopicId()}_{$oTopicRead->getUserId()}",
array(), 60 * 60 * 24 * 4);
$aTopicIdNeedStore = array_diff($aTopicIdNeedStore, array($oTopicRead->getTopicId()));
}
}
/**
* Сохраняем в кеш запросы не вернувшие результата
*/
foreach ($aTopicIdNeedStore as $sId) {
$this->Cache_Set(null, "topic_read_{$sId}_{$sUserId}", array(), 60 * 60 * 24 * 4);
}
/**
* Сортируем результат согласно входящему массиву
*/
$aTopicsRead = func_array_sort_by_keys($aTopicsRead, $aTopicId);
return $aTopicsRead;
}
/**
* Получить список просмотром/чтения топиков по списку айдишников, но используя единый кеш
*
* @param array $aTopicId Список ID топиков
* @param int $sUserId ID пользователя
* @return array
*/
public function GetTopicsReadByArraySolid($aTopicId, $sUserId)
{
if (!is_array($aTopicId)) {
$aTopicId = array($aTopicId);
}
$aTopicId = array_unique($aTopicId);
$aTopicsRead = array();
$s = join(',', $aTopicId);
if (false === ($data = $this->Cache_Get("topic_read_{$sUserId}_id_{$s}"))) {
$data = $this->oMapperTopic->GetTopicsReadByArray($aTopicId, $sUserId);
foreach ($data as $oTopicRead) {
$aTopicsRead[$oTopicRead->getTopicId()] = $oTopicRead;
}
$this->Cache_Set($aTopicsRead, "topic_read_{$sUserId}_id_{$s}", array("topic_read_user_{$sUserId}"),
60 * 60 * 24 * 1);
return $aTopicsRead;
}
return $data;
}
/**
* Получает топик по уникальному хешу(текст топика)
*
* @param int $sUserId
* @param string $sHash
* @return ModuleTopic_EntityTopic|null
*/
public function GetTopicUnique($sUserId, $sHash)
{
$sId = $this->oMapperTopic->GetTopicUnique($sUserId, $sHash);
return $this->GetTopicById($sId);
}
/**
* Рассылает уведомления о новом топике подписчикам блогов
*
* @param ModuleTopic_EntityTopic $oTopic Объект топика
* @param ModuleUser_EntityUser $oUserTopic Объект пользователя
*/
public function SendNotifyTopicNew($oTopic, $oUserTopic)
{
/**
* Сначала отправляем подписчикам блогов
*/
$iPage = 1;
$aBlogs = $oTopic->getBlogsId();
$aUserIdSend = array($oUserTopic->getId());
while ($aBlogUsersResult = $this->Blog_GetBlogUsersByBlogId($aBlogs, null, $iPage,
50) and $aBlogUsersResult['collection']) {
$aBlogUsers = $aBlogUsersResult['collection'];
foreach ($aBlogUsers as $oBlogUser) {
if (in_array($oBlogUser->getUserId(), $aUserIdSend)) {
continue;
}
$this->SendNotifyTopicNewToSubscribeBlog($oBlogUser->getUser(), $oTopic, $oBlogUser->getBlog(),
$oUserTopic);
$aUserIdSend[] = $oBlogUser->getUserId();
}
$iPage++;
}
/**
* Теперь отправляем авторам блогов
*/
$aBlogs = $this->Blog_GetBlogsAdditionalData($aBlogs);
foreach ($aBlogs as $oBlog) {
if ($oBlog->getOwnerId() != $oUserTopic->getId() and !in_array($oBlog->getOwnerId(), $aUserIdSend)) {
$this->SendNotifyTopicNewToSubscribeBlog($oBlog->getOwner(), $oTopic, $oBlog, $oUserTopic);
$aUserIdSend[] = $oBlog->getOwnerId();
}
}
}
/**
* Возвращает список последних топиков пользователя, опубликованных не более чем $iTimeLimit секунд назад
*
* @param int $sUserId ID пользователя
* @param int $iTimeLimit Число секунд
* @param int $iCountLimit Количество
* @param array $aAllowData Список типов данных для подгрузки в топики
* @return array
*/
public function GetLastTopicsByUserId($sUserId, $iTimeLimit, $iCountLimit = 1, $aAllowData = array())
{
$aFilter = array(
'topic_publish' => 1,
'user_id' => $sUserId,
'topic_new' => date("Y-m-d H:i:s", time() - $iTimeLimit),
);
$this->Hook_Run('get_topics_by_custom_filter',
array('aFilter' => &$aFilter, 'iPage' => 1, 'iPerPage' => $iCountLimit, 'sMethod' => __FUNCTION__));
$aTopics = $this->GetTopicsByFilter($aFilter, 1, $iCountLimit, $aAllowData);
return $aTopics;
}
/**
* Перемещает топики в другой блог
*
* @param int $sBlogId ID старого блога
* @param int $sBlogIdNew ID нового блога
* @return bool
*/
public function MoveTopics($sBlogId, $sBlogIdNew)
{
if ($res = $this->oMapperTopic->MoveTopics($sBlogId, $sBlogIdNew)) {
// перемещаем теги
$this->oMapperTopic->MoveTopicsTags($sBlogId, $sBlogIdNew);
// меняем target parent у комментов
$this->Comment_MoveTargetParent($sBlogId, 'topic', $sBlogIdNew);
// меняем target parent у комментов в прямом эфире
$this->Comment_MoveTargetParentOnline($sBlogId, 'topic', $sBlogIdNew);
/**
* Обновляем количество топиков в блоге
*/
$this->Blog_RecalculateCountTopicByBlogId($sBlogIdNew);
}
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("topic_update", "topic_new_blog_{$sBlogId}", "topic_new_blog_{$sBlogIdNew}"));
return $res;
}
/**
* Пересчитывает счетчик избранных топиков
*
* @return bool
*/
public function RecalculateFavourite()
{
return $this->oMapperTopic->RecalculateFavourite();
}
/**
* Пересчитывает счетчики голосований
*
* @return bool
*/
public function RecalculateVote()
{
return $this->oMapperTopic->RecalculateVote();
}
/**
* Алиас для корректной работы ORM
*
* @param array $aFilter Фильтр, который содержит список id топиков в параметре "id in"
* @return array
*/
public function GetTopicItemsByFilter($aFilter)
{
if (isset($aFilter['id in'])) {
return $this->GetTopicsByArrayId($aFilter['id in']);
}
return array();
}
/**
* Парсинг текста с учетом конкретного топика
*
* @param string $sText
* @param ModuleTopic_EntityTopic $oTopic
*
* @return string
*/
public function Parser($sText, $oTopic)
{
$this->Text_AddParams(array('oTopic' => $oTopic));
$sResult = $this->Text_Parser($sText);
$this->Text_RemoveParams(array('oTopic'));
return $sResult;
}
/**
* Возвращает объект типа топика по его коду
*
* @param string $sCode
*
* @return ModuleTopic_EntityTopicType|null
*/
public function GetTopicTypeByCode($sCode)
{
return $this->oMapperTopic->GetTopicTypeByCode($sCode);
}
/**
* Возвращает объект типа топика по его ID
*
* @param int $iId
*
* @return ModuleTopic_EntityTopicType|null
*/
public function GetTopicTypeById($iId)
{
return $this->oMapperTopic->GetTopicTypeById($iId);
}
/**
* Добавляет новый тип топика в БД
*
* @param ModuleTopic_EntityTopicType $oType
*
* @return ModuleTopic_EntityTopicType|bool
*/
public function AddTopicType($oType)
{
if ($sId = $this->oMapperTopic->AddTopicType($oType)) {
$oType->setId($sId);
//чистим зависимые кеши
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('topic_type_new'));
/**
* Регистрируем новый тип в дополнительных полях
* todo: fix lang text
*/
$this->Property_CreateTargetType('topic_' . $oType->getCode(),
array('entity' => 'ModuleTopic_EntityTopic', 'name' => 'Топик - ' . $oType->getName()), true);
return $oType;
}
return false;
}
/**
* @param array $aFilter
*
* @return mixed
*/
public function GetTopicTypeItems($aFilter = array())
{
return $this->oMapperTopic->GetTopicTypeItems($aFilter);
}
/**
* Обновляет тип топика в БД
*
* @param ModuleTopic_EntityTopicType $oType
*
* @return bool
*/
public function UpdateTopicType($oType)
{
return $this->oMapperTopic->UpdateTopicType($oType);
}
/**
* Удаляет тип топика из БД
*
* @param $sTypeId
*
* @return bool
*/
public function DeleteTopicType($sTypeId)
{
return $this->oMapperTopic->DeleteTopicType($sTypeId);
}
public function UpdateTopicByType($sType, $sTypeNew)
{
$res = $this->oMapperTopic->UpdateTopicByType($sType, $sTypeNew);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array("topic_update"));
return $res;
}
/**
* Формирует и возвращает полный ЧПУ URL для топика
*
* @param ModuleTopic_EntityTopic $oTopic
* @param bool $bAbsolute При false вернет относительный УРЛ
* @return string
*/
public function BuildUrlForTopic($oTopic, $bAbsolute = true)
{
$sUrlMask = Config::Get('module.topic.url');
$iDateCreate = strtotime($oTopic->getDatePublish());
$aReplace = array(
'%year%' => date("Y", $iDateCreate),
'%month%' => date("m", $iDateCreate),
'%day%' => date("d", $iDateCreate),
'%hour%' => date("H", $iDateCreate),
'%minute%' => date("i", $iDateCreate),
'%second%' => date("s", $iDateCreate),
'%login%' => '',
'%blog%' => '',
'%id%' => $oTopic->getId(),
'%title%' => $oTopic->getSlug(),
'%type%' => $oTopic->getType(),
);
/**
* Получаем связанные данные только если в этом есть необходимость
*/
if (strpos($sUrlMask, '%blog%') !== false) {
if (!($oBlog = $oTopic->GetBlog())) {
$oBlog = $this->Blog_GetBlogById($oTopic->getBlogId());
}
if ($oBlog) {
if ($oBlog->getType() == 'personal') {
$sUrlMask = str_replace('%blog%', '%login%', $sUrlMask);
} else {
$aReplace['%blog%'] = $oBlog->getUrl();
}
}
}
if (strpos($sUrlMask, '%login%') !== false) {
if (!($oUser = $oTopic->GetUser())) {
$oUser = $this->User_GetUserById($oTopic->getUserId());
}
if ($oUser) {
$aReplace['%login%'] = $oUser->getLogin();
}
}
$sUrl = strtr($sUrlMask, $aReplace);
return $bAbsolute ? Router::GetPathRootWeb() . '/' . $sUrl : $sUrl;
}
/**
* Формирует из строки url
*
* @param string $sText
* @return string
*/
public function MakeSlug($sText)
{
return $this->Text_Transliteration($sText);
}
/**
* Возвращает URL с учетом уникалькости по всем топикам
*
* @param string $sSlug
* @param int|null $iSkipTopicId
* @return string
*/
public function GetUniqueSlug($sSlug, $iSkipTopicId = null)
{
$iPostfix = 0;
do {
$sUrl = $sSlug . ($iPostfix ? '-' . $iPostfix : '');
$iPostfix++;
} while ($oTopic = $this->GetTopicBySlug($sUrl) and (is_null($iSkipTopicId) or $iSkipTopicId != $oTopic->getId()));
return $sUrl;
}
/**
* Отправляет юзеру уведомление об ответе на его комментарий
*
* @param ModuleUser_EntityUser $oUserTo Объект пользователя кому отправляем
* @param ModuleTopic_EntityTopic $oTopic Объект топика
* @param ModuleComment_EntityComment $oComment Объект комментария
* @param ModuleUser_EntityUser $oUserComment Объект пользователя, написавшего комментарий
* @return bool
*/
public function SendNotifyCommentReplyToAuthorParentComment(
ModuleUser_EntityUser $oUserTo,
ModuleTopic_EntityTopic $oTopic,
ModuleComment_EntityComment $oComment,
ModuleUser_EntityUser $oUserComment
) {
/**
* Проверяем можно ли юзеру рассылать уведомление
*/
if (!$oUserTo->getSettingsNoticeReplyComment()) {
return false;
}
$this->Notify_Send(
$oUserTo,
'comment_reply.tpl',
$this->Lang_Get('emails.comment_reply.subject'),
array(
'oUserTo' => $oUserTo,
'oTopic' => $oTopic,
'oComment' => $oComment,
'oUserComment' => $oUserComment,
)
);
return true;
}
/**
* Отправляет юзеру уведомление о новом топике в блоге, в котором он состоит
*
* @param ModuleUser_EntityUser $oUserTo Объект пользователя кому отправляем
* @param ModuleTopic_EntityTopic $oTopic Объект топика
* @param ModuleBlog_EntityBlog $oBlog Объект блога
* @param ModuleUser_EntityUser $oUserTopic Объект пользователя, написавшего топик
* @return bool
*/
public function SendNotifyTopicNewToSubscribeBlog(
ModuleUser_EntityUser $oUserTo,
ModuleTopic_EntityTopic $oTopic,
ModuleBlog_EntityBlog $oBlog,
ModuleUser_EntityUser $oUserTopic
) {
/**
* Проверяем можно ли юзеру рассылать уведомление
*/
if (!$oUserTo->getSettingsNoticeNewTopic()) {
return false;
}
$this->Notify_Send(
$oUserTo,
'topic_new.tpl',
$this->Lang_Get('emails.topic_new.subject') . ' «' . htmlspecialchars($oBlog->getTitle()) . '»',
array(
'oUserTo' => $oUserTo,
'oTopic' => $oTopic,
'oBlog' => $oBlog,
'oUserTopic' => $oUserTopic,
)
);
return true;
}
/**
* Регистрация сайтмапа для топиков
*/
public function RegisterSitemap()
{
$aFilter = array(
'blog_type' => array(
'open',
'personal',
),
'topic_publish' => 1,
'order' => 't.topic_id asc'
);
$this->Sitemap_AddTargetType('topics', array(
'callback_data' => function ($iPage) use ($aFilter) {
$aTopics = $this->GetTopicsByFilter($aFilter, $iPage, 500, array('blog' => array()));
$aData = array();
foreach ($aTopics['collection'] as $oTopic) {
$aData[] = $this->Sitemap_GetDataForSitemapRow(
$oTopic->getUrl(),
is_null($oTopic->getDateEdit()) ? $oTopic->getDatePublish() : $oTopic->getDateEdit(),
'0.9', 'weekly'
);
}
return $aData;
},
'callback_counters' => function () use ($aFilter) {
$iCount = (int)$this->GetCountTopicsByFilter($aFilter);
return ceil($iCount / 500);
}
));
}
}