Создание контроллера
Контроллер в Bitrix Framework — это PHP-класс, который обрабатывает AJAX-запросы от браузера. Он получает данные, выполняют бизнес-логику и формирует ответ.
В статье приведен пример, как в компонент my:user.card добавить функционал лайков. Для этого создадим контроллер, который будет:
-
принимать запросы на добавление и удаление лайков,
-
сохранять отметки в cookie-файлах,
-
возвращать текущее состояние.
Пример основан на модуле my.module и компоненте my:user.card, которые описаны в статьях:
Как работает вызов контроллера
Bitrix Framework связывает JavaScript-вызов и PHP-метод по имени — без дополнительной настройки. Это работает, когда соблюдаете три правила:
-
размещаете контроллер в папке
/lib/controller/модуля, -
объявляете класс в правильном пространстве имен,
-
вызываете действие контроллера по шаблону
vendor:module.ControllerName.actionName.
В примере модуль называется my.module. Bitrix Framework преобразует его имя в пространство имен. Первая часть my становится My, вторая module — Module, итого: My\Module.
Создайте файл контроллера, например, /lib/controller/user.php со следующим содержимым:
namespace My\Module\Controller;
class User extends \Bitrix\Main\Engine\Controller
{
public function likeAction()
{
// …
}
}
Теперь можно вызвать метод из JavaScript:
BX.ajax.runAction('my:module.user.like', { /* данные */ });
Система разбирает имя действия по частям:
-
my— первая часть символьного кода модуляmy.module, -
module— вторая часть символьного кода, -
user— имя класса контроллераUserв нижнем регистре, -
like— имя методаlikeAction()без суффиксаAction.
В результате система находит класс \My\Module\Controller\User и запускает метод likeAction().
Сопоставление работает, если в файле модуля .settings.php указан параметр defaultNamespace. Без этого Bitrix Framework не найдет класс и вернет ошибку.
Подробнее о правилах читайте в статье Контроллеры.
Структура модуля с контроллером
В структуре модуля my.module создайте файлы контроллера:
-
/lib/Services/LikeService.php— для класса-сервиса лайков, -
/lib/controller/user.php— для описания контроллера.
/local/modules/my.module/
├── install/
│ ├── components/
│ │ └── my/
│ │ └── user.card/ // Компонент карточки пользователя
│ │ ├── .description.php
│ │ ├── .parameters.php
│ │ ├── class.php
│ │ ├── templates/
│ │ │ └── .default/
│ │ │ ├── template.php
│ │ │ ├── script.js
│ │ │ └── style.css
│ │ └── lang/
│ │ └── ru/
│ │ └── messages.php
│ ├── index.php // Файл установки
│ └── version.php // Версия модуля
├── lib/
│ ├── controller/
│ │ └── user.php // Контроллер для обработки лайков
│ └── Services/
│ └── LikeService.php // Сервис для бизнес-логики
├── lang/
│ └── ru/
│ ├── install/
│ │ └── index.php // Языковой файл установки
│ └── messages.php // Общие языковые файлы
└── .settings.php // Настройка пространства имен контроллеров
Сервис для бизнес-логики
В файле /lib/Services/LikeService.php опишите класс LikeService для реализации логики работы с лайками. Чтобы обрабатывать лайки пользователей, добавьте в класс:
-
константу
COOKIE_NAME— имя cookie для храненияIDпользователей, в чьих карточках поставлены лайки. -
метод
isLiked— проверяет, поставлен ли лайк в карточке пользователя с идентификаторомuserId. -
метод
likeUser— добавляет идентификатор пользователя в список пользователей, в чьих карточках поставлен лайк. Если пользователь уже в списке, он не будет добавлен повторно. -
метод
dislikeUser— удаляет идентификатор пользователя из списка пользователей, которым поставлен лайк. -
метод
getLikedUsersIds— извлекает и декодирует список идентификаторов пользователей из cookie. -
метод
setLikedUsersIds— кодирует массив идентификаторов пользователей в формат JSON и сохраняет его в cookie, которые будут храниться 30 дней.
<?php
namespace My\Module\Services;
use Bitrix\Main\ArgumentException;
use Bitrix\Main\Context;
use Bitrix\Main\Web\Cookie;
use Bitrix\Main\Web\Json;
class LikeService
{
private const COOKIE_NAME = 'liked_users';
public function isLiked(int $userId): bool
{
return in_array($userId, $this->getLikedUsersIds());
}
public function likeUser(int $userId): void
{
$likedUsers = $this->getLikedUsersIds();
$likedUsers[] = $userId;
$this->setLikedUsersIds(
array_unique($likedUsers)
);
}
public function dislikeUser(int $userId): void
{
$likedUsers = array_filter($this->getLikedUsersIds(), static fn($i) => (int)$i !== $userId);
$this->setLikedUsersIds(
array_unique($likedUsers)
);
}
private function getLikedUsersIds(): array
{
try
{
$cookieValue = Context::getCurrent()->getRequest()->getCookie(self::COOKIE_NAME);
if (empty($cookieValue))
{
return [];
}
$value = Json::decode($cookieValue);
if (!is_array($value))
{
return [];
}
return $value;
}
catch (ArgumentException)
{
return [];
}
}
private function setLikedUsersIds(array $likedUsers): void
{
Context::getCurrent()->getResponse()->addCookie(
new Cookie(
self::COOKIE_NAME,
Json::encode($likedUsers),
time() + 60 * 60 * 24 * 30 // 30 days
)
);
}
}
Контроллер обработки лайков
В файле /lib/controller/user.php опишите контроллер User, который управляет действиями для обработки лайков.
Контроллер наследуется от \Bitrix\Main\Engine\Controller. Он не содержит бизнес-логику — только маршрутизацию, валидацию и вызов сервиса.
Добавьте два метода:
-
getDefaultPreFilters— определяет стандартные фильтры для всех действий, -
likeAction— обрабатывает действие лайка пользователя.
<?php
namespace My\Module\Controller;
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Engine\ActionFilter;
use Bitrix\Main\Error;
use My\Module\Services\LikeService;
class User extends Controller
{
/**
* Настройка фильтров для действий
*
* @return array
*/
protected function getDefaultPreFilters()
{
return [
// Разрешает запросы только авторизованным пользователям
new ActionFilter\Authentication(),
// Принимает только POST-запросы
new ActionFilter\HttpMethod([
ActionFilter\HttpMethod::METHOD_POST,
]),
// Проверяет CSRF-токен — защищает от подделки запроса
new ActionFilter\Csrf(),
];
}
/**
* Действие для обработки лайков
*
* @param int $likedUserId
*
* @return void
*/
public function likeAction(LikeService $service, int $likedUserId)
{
// Базовая валидация: ID должен быть положительным целым
if ($likedUserId < 1)
{
$this->addError(new Error('Неверный ID пользователя'));
return null;
}
// Если лайка нет — добавляем, иначе удаляем
$isLikeAction = !$service->isLiked($likedUserId);
if ($isLikeAction)
{
$service->likeUser($likedUserId);
}
else
{
$service->dislikeUser($likedUserId);
}
// Возвращаем состояние после изменения
return [
'liked' => $isLikeAction,
];
}
}
Интеграция с компонентом
Компонент my:user.card был создан ранее. Чтобы показывать информацию о лайках, внесите изменения в файлы компонента.
Шаблон template.php
В файле /install/components/my/user.card/templates/.default/template.php добавьте блок лайка с текстом Нравится.
-
Атрибут
data-user-idхранит идентификатор пользователя, карточку которого лайкают. Он нужен JavaScript. -
Класс
my-user-card__like-text—likedопределяет внешний вид активного лайка.
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
die();
use Bitrix\Main\Localization\Loc;
/**
* @var array $arParams
* @var array $arResult
* @var CMain $APPLICATION
* @var CBitrixComponent $component
* @var CBitrixComponentTemplate $this
*/
$additionalUserCardContainers = $arResult['HAS_LIKE'] ? 'my-user-card__like-text—liked' : '';
?>
<div class="my-user-card">
<?php if (isset($arResult['PERSONAL_PHOTO_SRC'])): ?>
<div class="my-user-card__avatar">
<img
class="js-my-user-card-avatar-show-in-new-page"
src="<?= $arResult['PERSONAL_PHOTO_SRC'] ?>"
alt="<?= $arResult['NAME'] ?>"
>
</div>
<?php endif; ?>
<div class="my-user-card__info">
<h2 class="my-user-card__name">
<?= $arResult['NAME'] ?>
</h2>
<?php if ($arParams['SHOW_EMAIL'] === 'Y'): ?>
<p class="my-user-card__email">
<span><?= Loc::getMessage('USER_CARD_EMAIL_LABEL') ?></span>
<span><?= $arResult['EMAIL'] ?></span>
</p>
<?php endif; ?>
</div>
<?php if ($USER->IsAuthorized()): ?>
<div class="my-user-card__like-container">
<span
class="my-user-card__like-text js-my-user-card-like <?= $additionalUserCardContainers ?>"
data-user-id="<?= $arParams['USER_ID'] ?>"
>
Нравится
</span>
</div>
<?php endif; ?>
</div>
Скрипт script.js
В файл /install/components/my/user.card/templates/.default/script.js добавьте обработку клика на текст Нравится.
BX.ready(() => {
// Обработка клика на аватар
document.querySelectorAll('.js-my-user-card-avatar-show-in-new-page').forEach((item) => {
BX.Event.bind(item, 'click', (e) => {
window.open(item.src, '_blank');
});
});
// Обработка клика на текст "Нравится"
document.querySelectorAll('.js-my-user-card-like').forEach((element) => {
BX.Event.bind(element, 'click', (e) => {
const userId = element.dataset.userId;
// Отправляем AJAX-запрос к контроллеру
BX.ajax.runAction(
'my:module.user.like',
{
data: { likedUserId: userId }
}
).then((response) => {
// Успешный ответ: обновляем внешний вид
if (response.status === 'success') {
if (response.data.liked)
{
element.classList.add('my-user-card__like-text—liked');
}
else
{
element.classList.remove('my-user-card__like-text—liked');
}
}
}).catch((response) => {
console.error('Error:', response.errors);
});
});
});
});
Стили style.css
В файл /install/components/my/user.card/templates/.default/style.css добавьте стили для текста лайка .
.my-user-card {
background: #cff9f2;
padding: 15px;
width: 230px;
}
.my-user-card__avatar {
margin: 0 0 15px 0;
}
.my-user-card__avatar img {
cursor: pointer;
max-width: 200px;
}
.my-user-card__info {
text-align: left;
}
.my-user-card__name {
font-size: 1.5rem;
margin: 0 0 10px 0;
}
.my-user-card__email {
font-size: 1rem;
}
.my-user-card__like-container {
margin-top: 10px;
}
.my-user-card__like-text {
cursor: pointer;
transition: color 0.3s ease, font-weight 0.3s ease;
user-select: none;
color: #999;
font-weight: normal;
}
.my-user-card__like-text:hover {
text-decoration: underline;
}
/* Активный лайк — синий и жирный */
.my-user-card__like-text—liked {
color: #0066cc;
font-weight: bold;
}
Класс компонента class.php
Внесите изменения в основной класс компонента /install/components/my/user.card/class.php:
-
подключите
ServiceLocatorиLikeService, -
в выборку пользователя добавьте поле
ID, -
в
arResultдобавьте проверку лайковHAS_LIKE, -
добавьте метод
isUserLiked(), который проверяет лайк черезLikeService.
<?php
use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\Loader;
use My\Module\Services\LikeService;
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
die();
}
class UserCardComponent extends CBitrixComponent
{
/**
* Подготавливаем входные параметры
*
* @param array $arParams
*
* @return array
*/
public function onPrepareComponentParams($arParams)
{
$arParams['USER_ID'] ??= 0;
$arParams['SHOW_EMAIL'] ??= 'Y';
return $arParams;
}
/**
* Основной метод выполнения компонента
*
* @return void
*/
public function executeComponent()
{
if (!Loader::includeModule('my.module'))
{
ShowError('Модуль my.module не установлен');
return;
}
// кешируем результат, чтобы не делать постоянные запросы к базе
if ($this->startResultCache())
{
$this->initResult();
// в случае если ничего не найдено, отменяем кеширование
if (empty($this->arResult))
{
$this->abortResultCache();
ShowError('Пользователь не найден');
return;
}
$this->includeComponentTemplate();
}
}
/**
* Инициализируем результат
*
* @return void
*/
private function initResult(): void
{
$userId = (int)$this->arParams['USER_ID'];
if ($userId < 1)
{
return;
}
$user = \Bitrix\Main\UserTable::query()
->setSelect([
'ID',
'NAME',
'EMAIL',
'PERSONAL_PHOTO',
])
->where('ID', $userId)
->fetch()
;
if (empty($user))
{
return;
}
$this->arResult = [
'NAME' => $user['NAME'],
'EMAIL' => $user['EMAIL'],
'HAS_LIKE' => $this->isUserLiked((int)$user['ID']),
];
// получаем путь до аватарки, в случае если она указана
if (!empty($user['PERSONAL_PHOTO']))
{
$this->arResult['PERSONAL_PHOTO_SRC'] = \CFile::GetPath($user['PERSONAL_PHOTO']);
}
}
/**
* Проверяем, поставил ли текущий пользователь лайк
*
* @return void
*/
private function isUserLiked(int $userId): bool
{
/**
* @var LikeService $service
*/
// Используем ServiceLocator, а не new LikeService(),
// чтобы компонент и контроллер работали с одним состоянием:
// если контроллер изменил cookie — компонент сразу увидит изменения
$service = ServiceLocator::getInstance()->get(LikeService::class);
return $service->isLiked($userId);
}
}
Настройка .settings.php
Файл /local/modules/my.module/.settings.php обязателен для работы контроллеров. Добавьте регистрацию контроллера. В результате становится возможен вызов my:module.user.like.
-
defaultNamespaceдолжен соответствовать пространству имен контроллера. -
Двойные обратные слеши
\\— экранирование в PHP-строках. -
readonly: trueзапрещает изменение настроек через интерфейс.
<?php
return [
'controllers' => [
'value' => [
'defaultNamespace' => '\\My\\Module\\Controller',
],
'readonly' => true,
]
];
Архив модуля с контроллером
Готовый модуль с контроллером можно скачать в архиве. Для работы распакуйте архив в папку /local/modules/.

Как разместить компонент на сайте
-
В административном разделе откройте страницу Marketplace > Установленные решения.
-
Установите модуль Мой модуль (my.module).
-
Создайте страницу и разместите на ней компонент Карточка пользователя.
После настройки компонента авторизованные пользователи увидят текст «Нравится» в карточке. Изначально текст будет серым, но, если поставить лайк, цвет изменится на синий.
