PC Magazine/RE - Журнал PC Magazine/RE №09/2009
Поиск других подходящих функций в модуле тоже не дал результата. Остается два пути. Первый – самостоятельно реализовать нужный нам метод. С точки зрения системного подхода, это более правильное решение, но... Здесь могут возникнуть проблемы обратной совместимости. Модуль довольно новый, мало ли что может измениться в недалеком будущем. Второй – получить необходимые данные, скомбинировав результаты нескольких стандартных методов, благо изучение исходных текстов модуля дает четкое представление, как это сделать. Вот и попробуем.
Общая идея выглядит так. Для объектов типа «пользователь» мы получаем списки идентификаторов пользователей-друзей и идентификаторов групп, для сущности «группа» – список идентификаторов пользователей-участников. Далее из списков идентификаторов пользователей исключаем тех, чьи записи не должны войти в «Ленту друзей». Аналогично обрабатываем список идентификаторов групп. Какие именно записи из блогов не должны включаться в ленты, мы выяснили при разборе свойств объектов «пользователь» и «группа». На основе созданных списков пользователей и групп составляем списки идентификаторов блогов, извлекаем необходимые записи и передаем их в шаблон для вывода на Web-странице, откуда был вызван компонент.
Для получения списка записей в блогах будем использовать функцию CBlogPost::GetList(). На первый взгляд, больше подходит функция CBlogUser::GetUserFriendsList(), которая специально предназначена для формирования списка сообщений друзей пользователя, но, к сожалению, она опирается на связи пользователей внутри модуля блогов, а не социальной сети, а это значит, что она нам не подходит. Функция же CBlogPost::GetList() возвращает список записей, соответствующих заданному фильтру, с возможностью сортировки и разбивки на страницы.
Включение в «Ленты» записей собственных блогов (для группы или пользователя) будем рассматривать как необязательное. Для ускорения обработки запросов и уменьшения нагрузки на сервер информацию, независящую от конкретного обратившегося посетителя, будем кэшировать. Итак, основные входящие параметры:
• $arParams['USER_ID'] – ID пользователя для построения ленты;
• $arParams['GROUP_ID'] – ID группы социальной сети для построения ленты;
• $arParams['BLOG_GROUP_ID'] – ID группы блогов, к которой принадлежат все блоги социальной сети;
• $arParams['INC_SELF_MESSAGES'] – включать ли в ленту сообщения из блога сущности.
Определение базовых прав пользователя, которые заодно будут использоваться как дополнительный идентификатор кэша (см. листинг 1). Обратим внимание на структуру $arResult['CURRENT_ACCESS']. В ней задаются права, доступные текущему пользователю по умолчанию. Далее получаем его идентификатор и определяем реальное состояние прав (листинг 2).
Листинг 1// Определим права текущего пользователя (который в данный
// момент смотрит "Ленту друзей")
$arResult = array();
// $arResult['ENTITY_TYPE'] – тип ленты,
// U – "лента пользователя", G – "лента группы"
$arResult['ENTITY_TYPE'] = $arParams['USER_ID'] >
0 ? 'U' : 'G';
// $arResult['ENTITY_ID'] – ID пользователя или группы
// (в зависимости от типа ленты)
$arResult['ENTITY_ID'] = $arResult['ENTITY_TYPE'] ==
'U' ? $arParams['USER_ID'] : $arParams['GROUP_ID'];
$arResult['CURRENT_ACCESS'] = array(
'canViewUserFriends' => false, //можно ли смотреть
// друзей пользователя
'canViewUserGroups' => false, // можно ли смотреть
// группы пользователя
'canViewUserSelfMessages' => false, // можно ли смотреть
// собственные записи
// блога пользователя
'canViewGroup' => false, // видима ли группа
'canViewGroupSelfMessages' => false // можно ли смотреть
// собственные записи
// блога группы
);
Листинг 2$isModuleAdmin = CSocNetUser::IsCurrentUserModuleAdmin();
$currentUserID = $GLOBALS['USER']->GetID();
if($arResult['ENTITY_TYPE'] == 'G') {
// для ленты групп проверим право на доступ к ней
$arResult['GROUP_INFO'] = CSocNetGroup::GetByID($arResult['ENTITY_ID']);
$arCurrentUserPerms = CSocNetUserToGroup::InitUserPerms($currentUserID, $arResult['GROUP_INFO'], $isModuleAdmin);
$arResult['CURRENT_ACCESS']['canViewGroup'] = $arCurrentUserPerms['UserCanViewGroup'];
unset($arCurrentUserPerms);
if($arParams['INC_SELF_MESSAGES'] && $arResult['CURRENT_ACCESS']['canViewGroup']) {
$arResult['CURRENT_ACCESS']['canViewGroupSelfMessages'] = CSocNetFeaturesPerms::CanPerformOperation($currentUserID,
SONET_ENTITY_GROUP, $arResult['ENTITY_ID'], 'blog', 'view_post', $isModuleAdmin);
}
} else {
//для ленты пользователя проверим доступ к ней текущего пользователя
$arCurrentUserPerms = CSocNetUserPerms::InitUserPerms($currentUserID, $arResult['ENTITY_ID'], $isModuleAdmin);
$arResult['CURRENT_ACCESS']['canViewUserFriends'] = $arCurrentUserPerms['Operations']['viewfriends'];
$arResult['CURRENT_ACCESS']['canViewUserGroups'] = $arCurrentUserPerms['Operations']['viewgroups'];
if($arParams['INC_SELF_MESSAGES']) {
// если не нужно включать в ленту сообщения из своего блога, то и проверять ID пользователя не будем
// (экономим на количестве кэш-файлов)
$arResult['CURRENT_ACCESS']['canViewUserSelfMessages'] = $currentUserID == $arResult['ENTITY_ID'];
}
unset($arCurrentUserPerms);
}
unset($currentUserID, $isModuleAdmin);
Значение $arResult['CURRENT_ACCESS'] и будет дополнительным идентификатором кэша:
if($this->StartResultCache(false, array($arNavigation,
$arResult['CURRENT_ACCESS']), $cachePath)) {
//код компонента
//подключение шаблона сохранения результатов в кэш.
$this->IncludeComponentTemplate();
}
где $arNavigation – массив управляющих параметров для постраничной навигации, $cachePath – путь для хранения кэш-файла. Определение идентификаторов друзей и групп для получения по ним ID блогов (исходный текст несколько сокращен для обозримости, листинг 3).
Листинг 3// массив идентификаторов пользователей, из блогов которых
// будут выбираться записи
$arEntityUsersID = array();
// массив идентификаторов групп, из блогов которых будут
// выбираться записи
$arEntityGroupsID = array();
if($arResult['ENTITY_TYPE'] == 'U') {
//лента пользователя
//можно ли смотреть друзей для данного пользователя,
// доступны ли вообще блоги и друзья
$getFriends = false;
if($arResult['CURRENT_ACCESS']['canViewUserFriends']) {
$getFriends = CPTK_SocialNetwork::IsAllowedFeature
(SONET_ENTITY_USER, 'blog') &&
CSocNetUser::IsFriendsAllowed();
}
// можно ли смотреть группы для данного пользователя
// и доступны ли вообще блоги для групп
if($arResult['CURRENT_ACCESS']['canViewUserGroups']) {
$getGroups = CPTK_SocialNetwork::IsAllowedFeature
(SONET_ENTITY_GROUP, 'blog');
}
Определим ID друзей пользователя (листинг 4).
Листинг 4if($getFriends) {
$arOrderUR = array();
$arFilterUR = array(
'RELATION' => SONET_RELATIONS_FRIEND,
'USER_ID' => $arResult['ENTITY_ID'],
);
$arGroupByUR = false;
$arNavigationUR = false;
$arSelectFieldsUR = array(
'FIRST_USER_ID',
'SECOND_USER_ID'
);
$rsItems = CSocNetUserRelations::GetList($arOrderUR,
$arFilterUR, $arGroupByUR, $arNavigationUR,
$arSelectFieldsUR);
while($arItem = $rsItems->Fetch())
{
$id_ = $arItem['FIRST_USER_ID'] ==
$arResult['ENTITY_ID'] ?
intval($arItem['SECOND_USER_ID']) :
intval($arItem['FIRST_USER_ID']);
$arEntityUsersID[$id_] = $id_;
}
unset($rsItems, $id_, $arOrderUR, $arGroupByUR,
$arNavigationUR, $arSelectFieldsUR);
}
Код исключения «закрытых» пользователей вынесен в конец модуля (он общий для двух типов лент). Схема довольно проста: добавим ID владельца в массив $arEntityUsersID, если включен режим вывода сообщений из блога владельца ленты. Здесь же важно заполнить записью массив $arEntityUsersID на случай, если пользователь запретил смотреть своих друзей (листинг 5).
Листинг 5if($arParams['INC_SELF_MESSAGES']) {
$arEntityUsersID[$arResult['ENTITY_ID']] =
$arResult['ENTITY_ID'];
}
// Определим ID видимых и НЕзакрытых групп пользователя
if($getGroups)
{
$arOrderGR = array();
$arFilterGR = array(
'USER_ID' => $arResult['ENTITY_ID'],
'<=ROLE' => SONET_ROLES_USER,
'GROUP_SITE_ID' => SITE_ID,
'GROUP_ACTIVE' => 'Y',
'GROUP_VISIBLE' => 'Y'
);
$arGroupByGR = false;
$arNavigationGR = false;
$arSelectFieldsGR = array(
'GROUP_ID',
'GROUP_NAME'
);
$rsItems = CSocNetUserToGroup::GetList($arOrderGR,
$arFilterGR, $arGroupByGR, $arNavigationGR,
$arSelectFieldsGR);
while($arItem = $rsItems->GetNext(false, false)) {
$id_ = intval($arItem['GROUP_ID']);
$arEntityGroupsID[$id_] = array(
'ID' => $id_,
'NAME' => $arItem['GROUP_NAME']
);
}
unset($rsItems, $id_, $arOrderGR, $arGroupByGR,
$arNavigationGR, $arSelectFieldsGR);
if(!empty($arEntityGroupsID)) {
//Определим группы, у которых блоги имеют статус
// приватных, и исключим их из списка
$arExceptGroupEntity = CPTK_SocialNetwork::
GetByRoleFeaturesIdArray(SONET_ENTITY_GROUP, 'blog',
'view_post', array('!ROLE' => SONET_ROLES_ALL),
array('!ROLE' => SONET_ROLES_ALL));
$arTmp = array_intersect_key($arExceptGroupEntity,
$arEntityGroupsID);
unset($arExceptGroupEntity);
if(!empty($arTmp)) {
foreach($arTmp as $key) {
unset($arEntityGroupsID[$key]);
}
}
unset($arTmp);
//Определим группы, в которых вообще отключены блоги,
// и исключим их из списка
$arExceptGroupEntity = CPTK_SocialNetwork::
GetByRoleFeaturesIdArray(SONET_ENTITY_GROUP, 'blog',
'view_post', array('FEATURE_ACTIVE' => 'N'),
array('FEATURE_ACTIVE' => 'N'));
$arTmp = array_intersect_key($arExceptGroupEntity,
$arEntityGroupsID);
unset($arExceptGroupEntity);
if(!empty($arTmp)) {
foreach($arTmp as $key) {
unset($arEntityGroupsID[$key]);
}
}
unset($arTmp);
}
}
Кроме того, необходимо обработать ситуацию, когда мы имеем дело с лентой для группы. Определяем, открыта ли группа для просмотра текущему пользователю, и вообще могут ли пользователи иметь блоги (листинг 6).