承接 beeralex/beeralex.reviews 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

beeralex/beeralex.reviews

最新稳定版本:v1.1.01

Composer 安装命令:

composer require beeralex/beeralex.reviews

包简介

My reviews module

README 文档

README

Система управления отзывами для Bitrix с поддержкой модерации, загрузки файлов и REST API.

Основные возможности

  • Создание отзывов с автоматической валидацией (PHP 8.1+ атрибуты)
  • 📁 Загрузка файлов (фото к отзывам)
  • 🔐 Модерация — новые отзывы требуют одобрения
  • 👤 Авторизованные и гостевые пользователи
  • Рейтинг 1-5 звезд
  • 📥 Импорт отзывов из 2GIS (deprecated)
  • 🔄 Сортировка (новые/старые)
  • 🌐 REST API интеграция

Требования

  • PHP 8.1+
  • Bitrix Framework 22.0+
  • Модуль beeralex.core (базовые абстракции)
  • Модуль beeralex.api (для REST API)
  • Инфоблок с кодом product_reviews

Установка

Через Composer

Добавьте в composer.json:

"extra": {
  "installer-paths": {
    "local/modules/{$name}/": ["type:bitrix-module"]
  }
}

Установите пакет:

composer require beeralex/beeralex.reviews

Ручная установка

  1. Разместите модуль в /local/modules/beeralex.reviews/
  2. Установите через административную панель Bitrix
  3. Модуль автоматически зарегистрирует сервисы

Настройка инфоблока

Создайте инфоблок с кодом product_reviews и свойствами:

USER_NAME       (string)  - Имя пользователя
EVAL            (number)  - Оценка (1-5)
REVIEW          (text)    - Текст отзыва
CONTACT_DETAILS (string)  - Email/телефон
ELEMENT_ID      (number)  - ID товара
USER            (number)  - ID пользователя Bitrix
FILES           (file)    - Фотографии (множественное)

Быстрый старт

Создание отзыва

use Beeralex\Reviews\Services\ReviewsService;
use Beeralex\Reviews\Dto\ReviewDTO;

$service = service(ReviewsService::class);

$dto = new ReviewDTO();
$dto->userName = 'Иван Петров';
$dto->eval = 5;
$dto->review = 'Отличный товар, рекомендую!';
$dto->contactDetails = 'ivan@example.com';
$dto->elementId = 123; // ID товара
$dto->userId = $USER->GetID() ?: null;

$result = $service->add($dto, $_FILES);

if ($result->isSuccess()) {
    $elementId = $result->getData()['elementId'];
    echo "Отзыв создан с ID: {$elementId}";
} else {
    foreach ($result->getErrorMessages() as $error) {
        echo "Ошибка: {$error}\n";
    }
}

Валидация данных

ReviewDTO использует атрибуты для автоматической валидации:

$dto = new ReviewDTO();
$dto->userName = 'А'; // Слишком короткое имя
$dto->eval = 6;       // Вне диапазона 1-5
$dto->review = 'OK';  // Слишком короткий отзыв

if (!$dto->isValid()) {
    foreach ($dto->getErrors() as $error) {
        echo $error->getMessage() . "\n";
    }
}

// Вывод:
// Имя должно быть от 2 до 100 символов
// Максимальная оценка - 5
// Отзыв должен быть от 10 до 5000 символов

Получение отзывов товара

use Beeralex\Reviews\Repository\ReviewsRepository;

$repo = service(ReviewsRepository::class);

$reviews = $repo->all(
    filter: [
        'IBLOCK_SECTION_ID' => 123, // ID товара
        'ACTIVE' => 'Y'
    ],
    select: [
        'ID',
        'DATE_CREATE',
        'PROPERTY_USER_NAME',
        'PROPERTY_EVAL',
        'PROPERTY_REVIEW',
    ],
    order: ['ID' => 'DESC']
);

foreach ($reviews as $review) {
    echo "{$review['PROPERTY_USER_NAME_VALUE']}: ";
    echo str_repeat('', $review['PROPERTY_EVAL_VALUE']);
    echo " - {$review['PROPERTY_REVIEW_VALUE']['TEXT']}\n";
}

REST API

Модуль интегрирован с beeralex.api через ReviewController.

Получить список отзывов

fetch('/api/v1/review/index/?product_id=123&count=10')
  .then(res => res.json())
  .then(data => console.log('Отзывы:', data));

Создать отзыв

const formData = new FormData();
formData.append('userName', 'Иван Петров');
formData.append('eval', 5);
formData.append('review', 'Отличный товар!');
formData.append('elementId', 123);
formData.append('files[]', fileInput.files[0]);

fetch('/api/v1/review/store/', {
  method: 'POST',
  body: formData
})
  .then(res => res.json())
  .then(data => {
    if (data.status === 'success') {
      console.log('Отзыв создан:', data.data.elementId);
    } else {
      console.error('Ошибки:', data.errors);
    }
  });

Ответ (успех):

{
  "status": "success",
  "data": {
    "elementId": 456
  }
}

Ответ (ошибка):

{
  "status": "error",
  "errors": [
    {
      "message": "Имя должно быть от 2 до 100 символов",
      "code": "review_create"
    }
  ]
}

Архитектура

Основные компоненты

ReviewsService              → Фасад для создания отзывов
├── ReviewCreatorService    → Логика создания, валидация
│   ├── UploadService       → Загрузка файлов
│   └── ReviewsRepository   → Работа с инфоблоком
└── ReviewDTO               → Валидация данных

Сервисы

ReviewsService — упрощенный интерфейс для добавления отзывов

ReviewCreatorService — реализация CreatorContract, содержит бизнес-логику

UploadService — реализация FileUploaderContract, загружает файлы через Bitrix CFile

ReviewsRepository — работа с инфоблоком отзывов (extends IblockRepository)

SortingRepository — статические варианты сортировки (новые/старые)

Расширение функционала

Добавление автоответа на отзыв

namespace App\Reviews\Services;

use Beeralex\Reviews\Services\ReviewCreatorService as BaseCreator;
use Beeralex\Reviews\Dto\ReviewDTO;
use Bitrix\Main\Result;

class ReviewCreatorService extends BaseCreator
{
    public function create(ReviewDTO $dto, array $files): Result
    {
        $result = parent::create($dto, $files);

        if ($result->isSuccess()) {
            $this->sendThankYouEmail($dto);
        }

        return $result;
    }

    protected function sendThankYouEmail(ReviewDTO $dto): void
    {
        \CEvent::Send('REVIEW_THANK_YOU', 's1', [
            'USER_NAME' => $dto->userName,
            'EMAIL' => $dto->contactDetails,
        ]);
    }
}

Зарегистрируйте в /local/.settings_extra.php:

use Beeralex\Reviews\Contracts\CreatorContract;
use App\Reviews\Services\ReviewCreatorService;

return [
    'services' => [
        'value' => [
            CreatorContract::class => [
                'constructor' => static function () {
                    return new ReviewCreatorService(
                        service(FileUploaderContract::class),
                        service(ReviewsRepository::class)
                    );
                }
            ],
        ]
    ]
];

Добавление проверки на спам

namespace App\Reviews\Services;

use Beeralex\Reviews\Services\ReviewCreatorService as BaseCreator;
use Beeralex\Reviews\Dto\ReviewDTO;
use Bitrix\Main\Result;
use Bitrix\Main\Error;

class ReviewCreatorService extends BaseCreator
{
    public function create(ReviewDTO $dto, array $files): Result
    {
        $result = new Result();

        if ($this->isSpam($dto)) {
            $result->addError(new Error('Отзыв отклонен как спам'));
            return $result;
        }

        return parent::create($dto, $files);
    }

    protected function isSpam(ReviewDTO $dto): bool
    {
        $spamWords = ['казино', 'кредит', 'займ'];
        $text = mb_strtolower($dto->review);

        foreach ($spamWords as $word) {
            if (str_contains($text, $word)) {
                return true;
            }
        }

        return false;
    }
}

Уведомления через beeralex.notification

namespace App\Reviews\Services;

use Beeralex\Reviews\Services\ReviewCreatorService as BaseCreator;
use Beeralex\Notification\NotificationManager;
use Beeralex\Notification\Dto\NotificationMessage;

class ReviewCreatorService extends BaseCreator
{
    public function create(ReviewDTO $dto, array $files): Result
    {
        $result = parent::create($dto, $files);

        if ($result->isSuccess()) {
            $this->notifyAdmin($dto, $result->getData()['elementId']);
        }

        return $result;
    }

    protected function notifyAdmin(ReviewDTO $dto, int $reviewId): void
    {
        $manager = new NotificationManager();

        $message = new NotificationMessage(
            eventName: 'NEW_REVIEW_MODERATION',
            fields: [
                'REVIEW_ID' => $reviewId,
                'USER_NAME' => $dto->userName,
                'RATING' => $dto->eval,
                'PRODUCT_ID' => $dto->elementId,
            ],
            userId: 1 // Администратор
        );

        $manager->notify($message);
    }
}

Импорт отзывов (deprecated)

⚠️ Устарело. Рекомендуется использовать API-интеграцию вместо импорта.

Импорт из 2GIS

use Beeralex\Reviews\Import\ImportFrom2Gis;

$importer = new ImportFrom2Gis(
    service: service(ReviewsService::class),
    branches: ['70000001234567890'], // ID филиалов 2GIS
    apiKey: 'your_2gis_api_key'
);

$importer->process();

Примеры компонентов

Форма добавления отзыва

class ReviewFormComponent extends CBitrixComponent
{
    public function executeComponent()
    {
        if ($this->request->isPost() && check_bitrix_sessid()) {
            $this->handleSubmit();
        }

        $this->includeComponentTemplate();
    }

    protected function handleSubmit(): void
    {
        $dto = new ReviewDTO();
        $dto->userName = $this->request->getPost('userName');
        $dto->eval = (int)$this->request->getPost('eval');
        $dto->review = $this->request->getPost('review');
        $dto->elementId = (int)$this->arParams['PRODUCT_ID'];
        $dto->userId = $GLOBALS['USER']->GetID() ?: null;

        $result = service(ReviewsService::class)->add($dto, $_FILES);

        if ($result->isSuccess()) {
            $this->arResult['SUCCESS'] = true;
        } else {
            $this->arResult['ERRORS'] = $result->getErrorMessages();
        }
    }
}

Список отзывов товара

class ReviewListComponent extends CBitrixComponent
{
    public function executeComponent()
    {
        $repo = service(ReviewsRepository::class);

        $this->arResult['REVIEWS'] = $repo->all(
            filter: [
                'IBLOCK_SECTION_ID' => $this->arParams['PRODUCT_ID'],
                'ACTIVE' => 'Y'
            ],
            select: [
                'ID', 'DATE_CREATE',
                'PROPERTY_USER_NAME',
                'PROPERTY_EVAL',
                'PROPERTY_REVIEW',
                'PROPERTY_FILES',
            ],
            order: ['ID' => 'DESC']
        );

        // Статистика
        $evals = array_column($this->arResult['REVIEWS'], 'PROPERTY_EVAL_VALUE');
        $this->arResult['AVERAGE_RATING'] = !empty($evals) 
            ? round(array_sum($evals) / count($evals), 1) 
            : 0;
        $this->arResult['TOTAL_COUNT'] = count($this->arResult['REVIEWS']);

        $this->includeComponentTemplate();
    }
}

Модерация

Все новые отзывы создаются с ACTIVE='N' и требуют одобрения.

Автоматическая модерация через агент

// В /local/php_interface/init.php
CAgent::AddAgent(
    "\\App\\Agents\\ReviewModerationAgent::moderate();",
    "", "N", 3600 // Каждый час
);

// Класс агента
namespace App\Agents;

class ReviewModerationAgent
{
    public static function moderate(): string
    {
        $repo = service(ReviewsRepository::class);

        // Одобрить отзывы 4-5 звезд от авторизованных
        $reviews = $repo->all([
            'ACTIVE' => 'N',
            '>=PROPERTY_EVAL' => 4,
            '!PROPERTY_USER' => false,
        ]);

        foreach ($reviews as $review) {
            $repo->update($review['ID'], ['ACTIVE' => 'Y']);
        }

        return "\\App\\Agents\\ReviewModerationAgent::moderate();";
    }
}

Зависимости

  • beeralex.core — Repository, FileService, AbstractRequestDto
  • beeralex.api — ReviewController
  • Bitrix/Main — Result, Error, Validation
  • Bitrix/Iblock — работа с инфоблоками

Документация

Полная документация доступна в docs/README.md

Лицензия

Проприетарный модуль. © beeralex

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-10-06