Blog 26.600.0: тег кеша для важных сообщений и исправленные права в уведомлениях
Blog 26.600.0 ничего не ломает и базу не трогает. Разработчику он даёт тег кеша blogpost_important_all и метод, который считает, сколько секунд осталось до ближайшей отложенной публикации важного сообщения. bitrix:blog.blog в папке модуля больше не перебирает все посты блога ради списка авторов, а на портале с intranet уведомления об упоминаниях и благодарностях считают права каждого получателя по его собственному типу пользователя.
Новое
Сбрасывайте свой кеш вместе с важными сообщениями
Модуль сбрасывает тег blogpost_important_all в двух местах. CBlogPost::Delete делает это после удаления важного поста. CBlogPost::Update сбрасывает тег, если пост был или стал важным и при этом поменялись флаг важности или срок UF_IMPRTANT_DATE_END, статус публикации, дата публикации, права SOCNET_RIGHTS или блог. Без BX_COMP_MANAGED_CACHE сброса нет. В коробке БУС тег никто не регистрирует, и кто читает его в Битрикс24, по её коду не проверить. Повесить на него свой кеш ничто не мешает.
У отложенного поста статус уже P, в списках он появляется, когда наступает DATE_PUBLISH, и в этот момент тег никто не сбрасывает. Для этого случая есть Bitrix\Blog\Integration\Socialnetwork\ImportantPostQuery::getNextPublicationDelay(DateTime $now, string $siteId): ?int. Метод находит по всем блогам, без учёта сайта и прав, ближайший важный пост с датой публикации в будущем и неистёкшим сроком важности и возвращает, через сколько секунд он выйдет (минимум 1). $siteId нужен только для формата даты. Если ждать нечего, вернёт null. Поле UF_BLOG_POST_IMPRTNT модуль blog сам не создаёт, и там, где его нет, запрос упадёт. Перед вызовом проверяйте hasField(), как это делает CBlogPost::Delete.
Файловый кеш, который стоит по умолчанию, применяет TTL из initCache() при чтении. Поэтому срок до публикации считаем один раз, при записи, кладём в сам кеш и сверяем после getVars(). Если раньше у важного поста сменят важность или её срок, статус, дату публикации, права или блог, запись сбросится по тегу. Правка заголовка и текста тег не сбрасывает.
<?php declare(strict_types=1);
use Bitrix\Blog\Integration\Socialnetwork\ImportantPostQuery;
use Bitrix\Blog\PostTable;
use Bitrix\Main\Application;
use Bitrix\Main\Data\Cache;
use Bitrix\Main\Loader;
use Bitrix\Main\Type\DateTime;
/** Виджет «Важное»: кеш до ближайшей отложенной публикации, но не дольше часа */
function getImportantWidget(string $siteId, callable $build): array
{
Loader::requireModule('blog');
$dir = '/vendor/important_widget';
$cache = Cache::createInstance();
if ($cache->initCache(3600, $siteId, $dir)) {
$vars = $cache->getVars();
if (is_array($vars) && ($vars['expiresAt'] ?? 0) > time()) {
return $vars['data'];
}
$cache->clean($siteId, $dir);
}
// срок считаем один раз, при записи: файловый кеш сверяет возраст с TTL из initCache()
$delay = PostTable::getEntity()->hasField('UF_BLOG_POST_IMPRTNT')
? (new ImportantPostQuery())->getNextPublicationDelay(new DateTime(), $siteId)
: null;
$expiresAt = time() + min(3600, $delay ?? 3600);
$cache->startDataCache(3600, $siteId, $dir);
$taggedCache = Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache($dir);
$taggedCache->registerTag('blogpost_important_all');
$data = $build();
$taggedCache->endTagCache();
$cache->endDataCache(['data' => $data, 'expiresAt' => $expiresAt]);
return $data;
}
CBlogPost::Add тег не сбрасывает, так что важный пост, опубликованный сразу, появится в виджете не позже чем через час, когда истечёт запись кеша. Если это долго, уменьшите верхнюю границу, но не убирайте её.
Источник «Блоги» в схеме уведомлений
CBlogNotifySchema::OnGetNotifySchema() теперь отдаёт в блоке blog ключ PRODUCT_SOURCE: ID blog, название «Блоги», описание «Комментарии и упоминания в ленте», иконка folder, сортировка 1500. Такой же ключ уже объявляют lists и mail. Читает его модуль im, которого в коробке БУС нет, поэтому где и как источник покажется в интерфейсе, по её коду не видно. Если хотите так же подписать уведомления своего модуля, повторите структуру blog в обработчике im:OnGetNotifySchema и проверьте результат на портале.
Обработчик регистрируем совместимым способом, как это делают blog, lists и mail:
<?php declare(strict_types=1);
namespace Vendor\Shop\Integration\Im;
use Bitrix\Main\EventManager;
use Bitrix\Main\Localization\Loc;
final class NotifySchema
{
public static function onGetNotifySchema(): array
{
return [
'vendor.shop' => [
'NAME' => Loc::getMessage('VENDOR_SHOP_NOTIFY_BLOCK'),
'PRODUCT_SOURCE' => [
'ID' => 'vendor.shop',
'NAME' => Loc::getMessage('VENDOR_SHOP_NOTIFY_SOURCE'),
'DESCRIPTION' => Loc::getMessage('VENDOR_SHOP_NOTIFY_SOURCE_DESC'),
'ICON' => ['TYPE' => 'named', 'VALUE' => 'folder'],
'SORT' => 2000,
],
'NOTIFY' => [
'order_new' => ['NAME' => Loc::getMessage('VENDOR_SHOP_NOTIFY_ORDER_NEW'), 'PUSH' => 'Y'],
],
],
];
}
/** Вызвать из DoInstall() модуля */
public static function register(): void
{
EventManager::getInstance()->registerEventHandlerCompatible(
'im', 'OnGetNotifySchema', 'vendor.shop', self::class, 'onGetNotifySchema',
);
}
/** Вызвать из DoUninstall() модуля */
public static function unregister(): void
{
EventManager::getInstance()->unRegisterEventHandler(
'im', 'OnGetNotifySchema', 'vendor.shop', self::class, 'onGetNotifySchema',
);
}
}
Deprecated
Замените getPostAuthorsIdsByBlogId
Bitrix\Blog\BlogUser::getPostAuthorsIdsByBlogId($blogId) помечен @deprecated (тикет 24773). Чтобы собрать ID авторов, метод выбирает все посты блога, хотя странице нужны только авторы того, что на ней показано. Докблок советует добавить AUTHOR_ID в select постраничной выборки и собирать ID в том же цикле. Так теперь работает bitrix:blog.blog, в getUsers() у него уходят только авторы текущей страницы. Если выборку трогать не хочется, вызывайте getPostAuthorsIdsByDbFilter() с фильтром страницы.
<?php declare(strict_types=1);
use Bitrix\Blog\BlogUser;
/** @param list<int> $pagePostIds ID постов, попавших на страницу */
function getPageAuthors(int $blogId, array $pagePostIds): array|false
{
if ($pagePostIds === []) {
return [];
}
// было: BlogUser::getPostAuthorsIdsByBlogId($blogId), то есть авторы всего блога
$authorIds = BlogUser::getPostAuthorsIdsByDbFilter(['ID' => $pagePostIds]);
$blogUser = new BlogUser(3600);
$blogUser->setBlogId($blogId);
return $blogUser->getUsers($authorIds);
}
В коробке БУС обновление поменяло только копию компонента в папке модуля (install/components), а /bitrix/components/bitrix/blog.blog/component.php по-прежнему вызывает старый метод. Копия компонента в local/ или в вашем namespace правку тоже не получит, переносите её вручную.
Мелочи и находки
- Права в уведомлениях.
CAllBlogPost::getCurrentUserType()хранил тип пользователя в статической переменной без привязки к ID, и все, кого проверяли в том же хите после первого, получали его тип.NotifyImвызываетGetSocNetPostPerms()для каждого упомянутого и для получателей благодарности, а от типа зависит, дадут ли запись в посты для G2/AU и чтение постов открытых групп. Если в посте упомянуты экстранет-пользователь и сотрудник, права второго считались по типу первого. Теперь тип запоминается по userId. Если ваш код за один хит проверяетCBlogPost::GetSocNetPostPerms()для разных пользователей, на портале с модулем intranet ошибка задевала и его, потому что все получали тип первого проверенного. - Опечатки в именах полей
UF_BLOG_POST_IMPRTNTиUF_IMPRTANT_DATE_ENDостались, новыйImportantPostQueryих повторяет. В своих фильтрах пишите так же.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
Bitrix\Blog\BlogUser::getPostAuthorsIdsByBlogId()
|
Deprecated |
Bitrix\Blog\BlogUser::getPostAuthorsIdsByDbFilter()
|