/
bitrix-dev
/
Starter-kit
Обзор
Документация
Войти
/
bitrix-dev
/
Starter-kit
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
main
local/php_interface/classes/mwi/ReviewManager.php
335 строк
12 KB
Alexey Karizhenskiy
Первая сборка (из ранее используемого)
19 янв 2026, 21:00
19 янв 2026, 21:00
d843e36
Код
Авторство
О чём код?
<?php namespace MWI; class ReviewManager { private string $uploadDir; private ?int $iblockId; public function __construct() { if (!\Bitrix\Main\Loader::includeModule("iblock")) { throw new \Exception("Не удалось подключить модуль инфоблоков"); } $this->iblockId = \MWI\Helper\Iblock::getIblockId('reviews_products'); $this->uploadDir = $_SERVER["DOCUMENT_ROOT"] . "/upload/tmp/reviews/"; } /** * Проверяет возможность добавления нового отзыва о товаре * * @param int $productId ID товара * @param int|null $userId ID пользователя (если не указан, то берется из глобальной переменной $USER) * @return bool Возможность добавления отзыва */ public function hasAllowAddItem(int $productId, int $userId = null): bool { if ($userId <= 0) { global $USER; $userId = (int)$USER->GetID(); } if ($userId <= 0) { // Если пользователь не авторизован, то разрешаем добавление отзыва return false; } // Проверяем существование товара $rsProduct = \CIBlockElement::GetList( [], ['ID' => $productId, 'ACTIVE' => 'Y'], false, false, ['ID'] ); if (!$rsProduct->Fetch()) { return false; } // Проверяем наличие отзыва за последние 10 дней $rsReview = \CIBlockElement::GetList( [], [ 'IBLOCK_ID' => $this->iblockId, 'PROPERTY_USER_ID' => $userId, 'PROPERTY_PRODUCT_ID' => $productId, '>=DATE_CREATE' => date('d.m.Y H:i:s', strtotime('-10 days')) ], false, false, ['ID'] ); if ($rsReview->Fetch()) { return false; } // Проверяем покупку товара if (\Bitrix\Main\Loader::includeModule('sale')) { $arProductIds = [$productId]; // Если товар имеет торговые предложения, то вначале получаем ID предложений if (\Bitrix\Main\Loader::includeModule('catalog')) { // Получаем все торговые предложения товара $rsOffers = \CCatalogSKU::getOffersList($productId); if (!empty($rsOffers[$productId])) { // Получаем первое предложение $arProductIds = array_keys($rsOffers[$productId]); } } $rsOrder = \Bitrix\Sale\Order::getList([ 'select' => ['ID'], 'filter' => [ 'USER_ID' => $userId, 'STATUS_ID' => 'F', // Статус "Выполнен" 'BASKET.PRODUCT_ID' => $arProductIds ] ]); if (!$rsOrder->fetch()) { return false; } } return true; } /* * Возвращает список отзывов о товаре * * @param int $productId ID товара * @param int $pageNumber Номер страницы отзывов * @param int $limit Количество отзывов на странице * @return array Список отзывов о товаре */ public function getReviews(int $productId, int $pageNumber = 1, int $limit = 30): array { $arResult = [ 'items' => [], 'rating' => 0, 'count' => 0 ]; $arFilter = [ 'IBLOCK_ID' => $this->iblockId, 'PROPERTY_PRODUCT_ID' => $productId, 'ACTIVE' => 'Y' ]; $arSelect = [ 'ID', 'IBLOCK_ID', 'NAME', 'DATE_CREATE', 'PREVIEW_TEXT' ]; $limit = max($limit, 1); $pageNumber = max($pageNumber, 1); $rsReviews = \CIBlockElement::GetList( ['DATE_CREATE' => 'DESC'], $arFilter, false, ['nPageSize' => $limit, 'iNumPage' => $pageNumber], $arSelect ); $arResult['count'] = $rsReviews->NavRecordCount; if ($rsReviews->NavRecordCount > $pageNumber * $limit) { $arResult['nextPage'] = $pageNumber + 1; } while ($obReview = $rsReviews->GetNextElement()) { $arReview = $obReview->getFields(); $arReview['PROPERTIES'] = $obReview->getProperties(); $arImages = []; if (!empty($arReview['PROPERTIES']['IMAGES']['VALUE']) && is_array($arReview['PROPERTIES']['IMAGES']['VALUE'])) { foreach ($arReview['PROPERTIES']['IMAGES']['VALUE'] as $imageId) { $arFile = \CFile::GetFileArray($imageId); if ($arFile) { $arImages[] = [ 'id' => $imageId, 'src' => \CFile::GetPath($imageId), 'preview' => \CFile::ResizeImageGet($imageId, ['width' => 200, 'height' => 200], BX_RESIZE_IMAGE_PROPORTIONAL)['src'] ]; } } } $arResult['items'][] = [ 'id' => $arReview['ID'], 'title' => $arReview['NAME'], 'name' => $arReview['PROPERTIES']['USER_NAME']['VALUE'] ?: $arReview['NAME'], 'rating' => (int)$arReview['PROPERTIES']['RATING']['VALUE'], 'comment' => $arReview['PREVIEW_TEXT'] ?? '', 'date' => $arReview['DATE_CREATE'], 'images' => $arImages, 'userId' => (int)$arReview['PROPERTIES']['USER_ID']['VALUE'] ]; } // Рейтинг товара - со свойства товара $arElement = \CIBlockElement::GetList( [], ['ID' => $productId], false, false, ['ID', 'IBLOCK_ID', 'PROPERTY_rating'] )->Fetch(); if ($arElement && $arElement['PROPERTY_RATING_VALUE']) { $arResult['rating'] = $arElement['PROPERTY_RATING_VALUE']; } return $arResult; } /** * Добавляет новый отзыв о товаре * * @param array $params Параметры отзыва * @return array Результат операции */ public function addReview(array $params): array { // Проверка обязательных полей $requiredFields = ['productId', 'name', 'rating', /*'comment'*/]; foreach ($requiredFields as $field) { if (!isset($params[$field]) || empty($params[$field])) { return [ 'success' => false, 'message' => "Поле {$field} обязательно для заполнения" ]; } } // Валидация значений if (!is_numeric($params['productId']) || $params['productId'] <= 0) { return [ 'success' => false, 'message' => 'Некорректный ID товара' ]; } if (!is_numeric($params['rating']) || $params['rating'] < 1 || $params['rating'] > 5) { return [ 'success' => false, 'message' => 'Оценка должна быть от 1 до 5' ]; } $userId = $params['userId'] ?? 0; if ($userId <= 0) { global $USER; $userId = (int)$USER->GetID(); } $isAllow = $this->hasAllowAddItem($params['productId'], $userId); if (!$isAllow) { return [ 'success' => false, 'message' => 'На данный момент вы не можете оставить отзыв на этот товар' ]; } $uploadedImages = $this->handleUploadedFiles($params['images'] ?? []); $el = new \CIBlockElement; $props = [ 'PRODUCT_ID' => (int)$params['productId'], 'USER_ID' => $userId, 'USER_NAME' => trim($params['name']), 'RATING' => (int)$params['rating'], 'IMAGES' => $uploadedImages ]; $fields = [ 'IBLOCK_ID' => $this->iblockId, 'NAME' => 'Отзыв на товар ' . $params['productId'] . ' от ' . trim($params['name']) . ' (' . date('Y-m-d H:i') . ')', 'PREVIEW_TEXT' => trim($params['comment']), 'PROPERTY_VALUES' => $props, 'ACTIVE' => 'N' ]; $elementId = $el->Add($fields); $this->cleanupTempFiles($uploadedImages); if ($elementId) { return [ 'success' => true, 'message' => 'Отзыв успешно добавлен и будет опубликован после модерации', 'id' => $elementId ]; } return [ 'success' => false, 'message' => 'Ошибка при добавлении отзыва: ' . $el->LAST_ERROR ]; } /** * Обрабатывает загруженные файлы * * @param array $files Массив файлов * @return array Обработанные файлы */ private function handleUploadedFiles(array $files): array { $uploadedImages = []; if (empty($files)) { return $uploadedImages; } if (!file_exists($this->uploadDir)) { mkdir($this->uploadDir, 0777, true); } foreach ($files as $file) { if (!empty($file["base64"]) && !empty($file["type"])) { // Проверяем на base64 $fileName = !empty($file["tmp_name"]) ? $file["tmp_name"] : (uniqid() . "." . basename($file["type"])); $filePath = $this->uploadDir . $fileName; if (file_put_contents($filePath, base64_decode($file["base64"]))) { $arFile = \CFile::MakeFileArray($filePath); if ($arFile) { $uploadedImages[] = $arFile; } } } elseif (isset($file["tmp_name"])) { // Проверяем, что файл загружен if ($file["error"] === UPLOAD_ERR_OK) { $fileName = uniqid() . "_" . basename($file["name"]); $filePath = $this->uploadDir . $fileName; if (move_uploaded_file($file["tmp_name"], $filePath)) { $arFile = \CFile::MakeFileArray($filePath); if ($arFile) { $uploadedImages[] = $arFile; } } } } } return $uploadedImages; } /** * Очищает временные файлы * * @param array $uploadedImages Массив загруженных изображений */ private function cleanupTempFiles(array $uploadedImages): void { if (!empty($uploadedImages)) { foreach ($uploadedImages as $image) { if (file_exists($image['tmp_name'])) { unlink($image['tmp_name']); } } } } }