403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/burlakastudio.realcommenter/lib/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/burlakastudio.realcommenter/lib/Comments.php
<?php
/**
 * ����� "��������� ����������� D7" ��� �������
 * �������� ���� �����: www.realcommenter.com
 * �������� ���� �����������: burlaka.studio
 * ����� � ����������: ������� ������� (AlexeyGfi) -> alexeygfi@gmail.com
 */

namespace Burlakastudio\Realcommenter;

use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ORM\Data\Result;
use Bitrix\Main\ORM\Fields\Relations\OneToMany;
use Bitrix\Main\ORM\Fields\Relations\Reference;
use Bitrix\Main\ORM\Objectify\EntityObject;
use Bitrix\Main\ORM\Query\Join;
use Bitrix\Main\ORM\Query\Query;
use Bitrix\Main\Type\DateTime;
use CTimeZone;
use Exception;
use RuntimeException;

require_once 'COMMENTS_TABLE.php';

class Comments extends REALCOMMENTER_HL_GENERAL_PROVIDER
{

    /**
     * �������� �� ���������� ����������,
     * ... ������ �� ����������� �� ������� (�� ������� ����, �������� ���������� � ��������)
     *
     * @param array $arParams
     *
     * @return mixed|string
     */
    public static function calculateActive(&$arParams = [])
    {

        if (GRANT_AND_ACCESS::is_any_moder($arParams)) {
            return 1;
        }

        if (!empty($arParams['PREMODERATING_FOR'])) {
            $premoderatingFor =
                array_values(
                    array_filter(
                        array_unique($arParams['PREMODERATING_FOR'])));
        }

        if (!empty($premoderatingFor)) {

            if (
                !USER::get_id()
                && in_array('U', $premoderatingFor)
            ) {
                return 0;
            }

            /**
             * �� ��� � ��-���� �����������
             *
             * ��� �������� � ������, ������ ������� ��� ��, ������� �� �������
             * ��������� �� ����������
             */
            $userGroups = USER::get_user_groups();
            if (array_intersect($userGroups, $premoderatingFor)) {
                return 0;
            }

        }

        /**
         * �����, ��� arParams ����� ������ ��� ��������������,
         * �� ��� ��� API - ��� �����...
         */
        return (int)($arParams['ACTIVE_FOR_NEW'] === true || $arParams['ACTIVE_FOR_NEW'] === 'Y');

    }

    /**
     * ������ ���� �����������: ����� � ������������� ������
     * (����������� ���� ���???) � ����, ��� �����-�� ������ ����� �������� ������� �������
     *
     * ������� �����:
     *      - �� ��������� ����������
     *      - ����� ��������� ����������
     *      - ���� �����������
     *      - ���������� �����
     *
     * =======
     * ���� �� ����� �����:
     *
     * ������� ������� ���������� � �������� ������� - �������� ������ ������ ��� ���������
     * � �������� ����� �� ������������
     *
     * ������� �� ��� ���������
     *
     * �������� ������ ������������ � ����� (���� ��������� ���� � �������� �����-������)
     * ������ �� ����
     *
     * �������� ����������:
     * !) ������� ������ ���: tape_general_title, tape_user_text
     *      - ������ ����������, �� ������ �������� �����
     *      - ���� ��� ����� �� ������ ����������� - ����, ��� ������� ���� ����� ����� �� ��� �� ������, ��� � ���� ����������
     *      - �������
     *      - ����������
     *      - ���, ��� ��������� ������ �� ����������� �� ���� (�������� �������)
     *      - ���, ��� ��������� ������ �� ����������� �� ���� (���� ������� - ����� tape_user_id ��� tape_user_email)
     *
     * @param array $commentInfo
     * @param array $arParams
     *
     * @return bool
     * @throws Exception
     */
    public static function new_comment($commentInfo = [], &$arParams = [])
    {

        $newRow = self::get_free_row([
            'UF_URL_ID' => false
        ]);

        if (!$newRow || !$newRow['ID']) {
            throw new Exception('COMMENTS_DB_ERROR');
        } else {

            /**
             * �����, ������ ���� ������ ����, ������� ����������.
             * � � ����������� ��� ���� ��������� ���.
             *
             * ...��� �����, ��� � ��� ����� ��� ����������, ������ ����
             */
            $commentInfo['ADDI'] = $commentInfo['ADDI'] ?? null;

            if ($commentInfo['ADDI']) {
                AdditionalFieldsValues::attachForComment(
                    (int)$newRow['ID'],
                    $commentInfo['ADDI'],
                    $arParams
                );
            }

            unset($commentInfo['ADDI']);

            EVENT::call('OnBeforeCommentAdd', [
                'comment_info' => &$commentInfo,
                'arParams' => &$arParams
            ]);

            $check_result = new Result();
            COMMENTS_TABLE::checkFields($check_result, null, $commentInfo);

            if ($check_result->isSuccess()) {

                self::fixZeroNull($commentInfo);

                /**
                 * ������ ���� �� �������
                 */
                CTimeZone::Disable();

                if (!$commentInfo['UF_CREATED_DATE']) {
                    $commentInfo['UF_CREATED_DATE'] = new DateTime();
                }

                // $update_result =
                self::update($newRow['ID'], $commentInfo);

                CTimeZone::Enable();

                // ����� ��������. ��������
                $commentInfo['ID'] = $newRow['ID'];
                CACHE::commentsCacheComplexDrop($commentInfo);

                $commentInfo = (array)self::getCommentInfo($newRow['ID']);

                EVENT::call('OnAfterCommentAdd', [
                    'comment_info' => $commentInfo,
                    'comment_id' => $commentInfo['ID'],
                    'arParams' => $arParams,
                ]);

                return $commentInfo['ID'];

            } else {

                throw new Exception(implode(', ', $check_result->getErrorMessages()));
            }

        }

    }

    /**
     * ����� ���� �������� ������:
     * �������� ��� ����� ������������� �� ������� ����� ����� 0 � NULL.
     *
     * � ��� ������� �� �����, �� ������ � ������ ����������,
     * �������� NULL ���������� ���� ��� 0
     *
     * �������� � ���������� ������: ���� ���� �� ����� ������� (��� ���),
     * ������ ��� NULL
     *
     * @param array $commentInfo
     */
    private static function fixZeroNull(&$commentInfo = [])
    {

        $zeroNullFields = [
            'UF_VOTES_MINUS',
            'UF_VOTES_PLUS',
            'UF_RATE_VALUE',
            'UF_PARENT_ID'
        ];


        foreach ($zeroNullFields as $zf) {
            if (isset($commentInfo[$zf]) && !$commentInfo[$zf]) {
                $commentInfo[$zf] = null;
            }
        }
    }

    public static function getCommentInfo($id = 0/*, &$urlInfo = []*/)
    {
        if (!$id) {
            return false;
        }

        $cacheObj = CACHE::getCacheObj();
        $cacheKey = CACHE::getKeyForSingleComment($id);
        $cacheTtl = CACHE::getTtl();

        $result = [];

        /**
         * By the way, cache should be always
         */
        if ($cacheObj->initCache($cacheTtl, $cacheKey, TOOLS::getModuleName())) {
            // ���� �� ���
            $result = $cacheObj->getVars();

        } else {
            $entity = OrmHelper::compileEntity('RealcommenterComment');
            $urlEntity = OrmHelper::compileEntity('RealcommenterUrl');

            if ($entity && $urlEntity) {

                /**
                 * When we reuse entity objects,
                 * they are already has additional fields
                 */
                if (!$entity->hasField('URL')) {
                    $entity->addField(
                        (new Reference('URL',
                            $urlEntity,
                            Join::on('this.UF_URL_ID', 'ref.ID')
                        ))->configureJoinType(Join::TYPE_RIGHT)
                    );
                }

                $queryResult =
                    (new Query($entity))
                        ->addFilter('ID', $id)
                        ->setSelect(['URL_ID' => 'URL.ID'])
                        ->setLimit(1)
                        ->exec();

                if ($arr = $queryResult->fetch()) {

                    $urlId = $arr['URL_ID'] ?? null;
                    if ($urlId) {
                        $list = self::loadRawTreeByUrlId($urlId);
                        $result = array_filter($list, static function ($commentInfo) use ($id) {
                            return $commentInfo['ID'] == $id;
                        });

                        if (!empty($result)) {
                            $result = array_shift($result);
                        }
                    }
                }
            }
        }

        return $result;
    }

    /**
     * � ��� �������� ������� ��������������� ���� UF_URL_ID,
     * ������� ���������� ������� �������������� ����������, ��� ����������� �� ������ �����������
     *
     * ����� ������� � ����� ����� �������� ����� ��� ����������� �� ����������� ��� ����
     *
     * � ��� ������ ��� ������ ������
     * ...���������� ��� ����������, ��������, �������������� ����� ��������
     *
     * @param int $urlId
     * @return array
     * @throws \Bitrix\Main\ArgumentException
     * @throws \Bitrix\Main\ObjectPropertyException
     * @throws \Bitrix\Main\SystemException
     */
    private static function loadRawTreeByUrlId(&$urlId = 0)
    {
        if (!$urlId) {
            return [];
        }

        $result = [];

        $cacheObj = CACHE::getCacheObj();
        $cacheKey = CACHE::get_url_key_for_comments($urlId);
        $cacheTtl = CACHE::getTtl();

        /**
         * ���� � ��� ���������� ������.
         *
         * ���� ����� � ��������� ���������� ����� ������� ���������� ����������
         * (� ��� ��������� ����� � ����� ������� �����)
         * ...������ ��� ���� ������� ������ �������� ��� ������� ����� � ������� �������.
         *
         * ���������� ���� ��������� ����� �� ����� ������� �����
         * ... �� ��� ���� � ������
         */

        if ($cacheObj->initCache($cacheTtl, $cacheKey, TOOLS::getModuleName())) {
            // ���� �� ���
            $result = $cacheObj->getVars();
        } else {

            CTimeZone::Disable();

            $entity = OrmHelper::compileEntity('RealcommenterComment');
            $addiFieldsValuesEntity = AdditionalFieldsValues::compileEntity();

            if (!$entity || !$addiFieldsValuesEntity) {
                return $result;
            }

            /**
             * When we reuse entity objects,
             * they are already has additional fields
             */
            if (!$addiFieldsValuesEntity->hasField('COMMENT')) {
                $addiFieldsValuesEntity->addField(
                    (new Reference(
                        'COMMENT',
                        $entity,
                        Join::on('this.UF_COMMENT_ID', 'ref.ID')
                    ))
                );
            }

            if (!$entity->hasField('ADDI_VALUES')) {
                $entity->addField(
                    (new OneToMany(
                        'ADDI_VALUES',
                        $addiFieldsValuesEntity,
                        'COMMENT'
                    ))
                );
            }

            if (!$entity->hasField('URL')) {
                $urlEntity = OrmHelper::compileEntity('RealcommenterUrl');

                $entity->addField(
                    (new Reference('URL',
                        $urlEntity,
                        Join::on('this.UF_URL_ID', 'ref.ID')
                    ))->configureJoinType(Join::TYPE_RIGHT)
                );
            }

            if ($entity) {
                $queryResult =
                    (new Query($entity))
                        ->addFilter('UF_URL_ID', $urlId)
                        ->setOrder(
                            [
                                /**
                                 * �� ����� �����������
                                 */
                                'UF_DEPTH_LEVEL' => 'ASC',

                                /**
                                 * �� ������������ ����������
                                 * (��� ��� ���� - ���������� ����� ����������� ���� ����� ID,
                                 * ��� ���������� �����
                                 */
                                'UF_PARENT_ID' => 'ASC',

                                /**
                                 * �� ���� == ����� ���� ����, ����� ������� � �����
                                 */
                                'UF_CREATED_DATE' => 'ASC',

                                /**
                                 * ��������� �����
                                 */
                                'ID' => 'ASC'
                            ]
                        )
                        ->setSelect([
                            '*', 'ADDI_VALUES',
                            'COMMENT_GROUP_ID' => 'URL.UF_GROUP_ID'
                        ])
                        ->exec();

                /**
                 * @var EntityObject $obj
                 */

                $groupsIdList = [];

                $skipKeys = [
                    'ADDI_VALUES',
                    'URL'
                ];

                while ($obj = $queryResult->fetchObject()) {
                    $arr = $obj->collectValues();

                    $arrAddiValues = [];

                    foreach ($obj->getAddiValues() as $addiObj) {
                        $arrAddiValues[] = $addiObj->collectValues();

                        $arr['AF_VALUES'] = $arr['AF_VALUES'] ?? [];
                        $arr['AF_VALUES'][$addiObj->getUfFieldId()] = $addiObj->getUfValue();
                    }

                    $commentGroupId = $arr['URL']->get('UF_GROUP_ID') ?? null;
                    $arr['COMMENT_GROUP_ID'] = $commentGroupId;
                    $groupsIdList[] = $commentGroupId;

                    if (self::hasUnmoderatedAddiFields($arrAddiValues)) {
                        // More useful get in this key list of approval awaiting fields
                        // $arr['AF_PROOF_AWAITING'] = true;

                        $arr['AF_PROOF_AWAITING'] = array_filter(
                            $arrAddiValues,
                            static function ($value) {
                                return $value['UF_MODERATED'] !== true;
                            }
                        );

                        $arr['AF_PROOF_AWAITING'] = array_reduce(
                            $arr['AF_PROOF_AWAITING'],
                            static function ($carry, $item) {
                                $carry[] = $item['ID'];
                                return $carry;
                            }, []
                        );

                        $arr['AF_ACTIVE'] = false;
                    }

                    $arr = array_filter($arr, static function ($key) use ($skipKeys) {
                        return !in_array($key, $skipKeys);
                    }, ARRAY_FILTER_USE_KEY);

                    if ($cacheObj->startDataCache(
                        $cacheTtl,
                        CACHE::getKeyForSingleComment($arr['ID'])
                    )) {
                        // ���� � �� ��������� �����������
                        $cacheObj->endDataCache($arr);
                    }

                    $result[] = $arr;
                }
            }

            CTimeZone::Enable();

            $groupsIdList = array_filter($groupsIdList);
            $groupsIdList = array_unique($groupsIdList);

            /**
             * �������� � ������� ��� � ����� �������� � int-�
             */
            foreach ($result as & $row) {
                TOOLS::normalizeValues($row, [
                    'UF_COMMENT',
                    'UF_SIGNATURE',
                    'UF_EMAIL',
                    'UF_CREATED_DATE',
                    'UF_UPLOADS'
                ]);
            }
            unset($row);

            $addiFields = AdditionalFields::getFieldsByGroup(reset($groupsIdList));
            /**
             * �������� ����� ��� ����� "��������� ����"
             */

            if ($addiFields) {
                $addiFields = array_filter($addiFields, function ($item) {
                    return $item['UF_TYPE'] == 'text';
                });
            }

            /**
             * �������� ��� � ������ ��������, ���� �������� �� ���
             */
            foreach ($result as & $row) {
                $row = array_filter($row);
                PARSER::processMsgForPublish($row['UF_COMMENT']);
                // TODO: Process AF_ fields
                foreach ($addiFields as $fieldId => $fieldSettings) {
                    $fieldValue = $row['AF_VALUES'][$fieldId] ?? null;
                    if ($fieldValue) {
                        PARSER::processMsgForPublish($row['AF_VALUES'][$fieldId]);

                        $row['AF_VALUES'][$fieldId] = str_replace("\n", '<br>', $row['AF_VALUES'][$fieldId]);
                    }
                }

            }
            unset($row);

            if ($cacheObj->startDataCache($cacheTtl, $cacheKey)) {
                // ���� � ��
                $cacheObj->endDataCache($result);
            }
        }

        return $result;
    }

    protected static function hasUnmoderatedAddiFields($additionalFields = [])
    {
        return !empty(
        array_filter(
            $additionalFields,
            static function ($value) {
                return $value['UF_MODERATED'] !== true;
            }
        )
        );
    }

    public static function OnAfterUpdate(\Bitrix\Main\ORM\Event $event)
    {
        $commentInfo = $event->getParameter('fields');
        $commentId = $event->getParameter('id');

        EVENT::call('OnAfterCommentUpdate', [
            'comment_info' => $commentInfo,
            'comment_id' => $commentId['ID'],
//            'arParams' => $arParams,
        ]);
    }

    public static function approveComment($id = null, &$arParams = [])
    {
        if (!$id) {
            return;
        }

        /**
         * ��������, �� ���� �� ��� ����������
         */
        $info = self::getCommentInfo($id);
        if (!$info) {
            return;
        }

        $afProofAwaiting = $info['AF_PROOF_AWAITING'] ?? null;
        if ($afProofAwaiting) {
            foreach ($afProofAwaiting as $fieldValueId) {
                EVENT::call('OnBeforeAdditionalFieldModerate', [
                    'fieldId' => &$fieldValueId,
                ]);

                AdditionalFieldsValues::update($fieldValueId, ['UF_MODERATED' => true]);

                EVENT::call('OnAfterAdditionalFieldModerate', [
                    'fieldId' => &$fieldValueId,
                ]);
            }
        }

        $ufProofAwaiting = $info['UF_PROOF_AWAITING'] ?? null;
        if ($ufProofAwaiting) {
            EVENT::call('OnBeforeCommentModerate', [
                'commentInfo' => &$info,
                'commentId' => &$id,
                'arParams' => &$arParams
            ]);

            self::updateSingle($id, ['UF_PROOF_AWAITING' => false], $arParams, true);
//            self::makeActive($id, $arParams, true);

            EVENT::call('OnAfterCommentModerate', [
                'commentInfo' => &$info,
                'commentId' => &$id,
                'arParams' => &$arParams
            ]);
        }

        if ($afProofAwaiting || $ufProofAwaiting) {
            // ������ �� ������ ��
            self::makeActive($id, $arParams, true);
        }
    }

    /**
     * @param null $commentId
     * @param array $dataToSave
     * @param array $arParams
     * @param bool $skipEvents ���� � ���������� ����������� ����� ����� �����,
     *                          �������� �� ���������� �����
     *                          - ����� �������� �� �������� �����
     *
     * @return bool
     * @throws Exception
     */
    public static function updateSingle($commentId = null, $dataToSave = [], &$arParams = [], $skipEvents = false)
    {

        if (!$commentId) {
            return false;
        }

        $info = self::getCommentInfo($commentId);
        if (!$info) {
            return false;
        }

        /**
         * ��� �������������� ��� ������ � ������� ����� ������ ��:
         *      - �� UF_UPLOADS
         *          == ���� ���������� ����, � ������� � ����� ����������
         *      - �� UF_UPLOADED_TO_DEL
         *          == ������ �� UF_UPLOADS id-���, ������ ��� � �������
         *
         */

        $uploads = [];
        if (
            ($dataToSave['UF_UPLOADS'] && !empty($dataToSave['UF_UPLOADS'])) ||
            ($dataToSave['UF_UPLOADED_TO_DEL'] && !empty($dataToSave['UF_UPLOADED_TO_DEL']))
        ) {
            // ������������ �� ����, ��� ��� ��������
            if (is_array($info['UF_UPLOADS'])) {
                $uploads = $info['UF_UPLOADS'];
            } else if ($info['UF_UPLOADS']) {
                $uploads = unserialize($info['UF_UPLOADS'], ['allowed_classes' => false]);
            }

            if (!is_array($uploads)) {
                $uploads = [];
            }

            if ($dataToSave['UF_UPLOADS']) {
                $uploads = array_merge($uploads, $dataToSave['UF_UPLOADS']);
            }

            if ($dataToSave['UF_UPLOADED_TO_DEL']) {
                $uploads = array_diff($uploads, $dataToSave['UF_UPLOADED_TO_DEL']);
                unset($dataToSave['UF_UPLOADED_TO_DEL']);
            }

            $dataToSave['UF_UPLOADS'] = serialize($uploads);

        }

        $dataToSave = self::filterRealUpdatedFields($dataToSave, $info, $arParams);
        if (empty($dataToSave)) {
            return false;
        }

        if (!$skipEvents) {
            EVENT::call('OnBeforeCommentUpdate', [
                'comment_info' => &$dataToSave,
                'arParams' => &$arParams
            ]);
        }

        self::fixZeroNull($dataToSave);
        $result = self::update($commentId, $dataToSave);

        if ($result->isSuccess()) {

            if (!$skipEvents) {
                EVENT::call('OnAfterCommentUpdate', [
                    'comment_info' => $dataToSave,
                    'comment_id' => $commentId,
                    'arParams' => $arParams,
                ]);
            }

        } else {
            throw new RuntimeException(implode(', ', $result->getErrorMessages()));
        }

        return true;
    }

    /**
     * ��� ��� ������� - ���� ��� � ������.
     * ����� ������ ��� ����� �����������
     *      ���-�� ������ �� ������ ���� � ����������
     *      ��� � ����� ������� ����� �������������
     * ...� ������� � �������� ����� �����
     *
     * @param array $fieldsNew
     * @param array $fieldsOld
     * @param array $arParams
     *
     * @return array
     */
    public static function filterRealUpdatedFields($fieldsNew = [], &$fieldsOld = [], &$arParams = [])
    {

        $moderatorAccessKeys = self::getModeratorAccessKeys();

        unset($fieldsNew['ID']);

        /**
         * �� ���������.
         * �� ����� ������� ����� � ������������ �����
         */
        if (
            !GRANT_AND_ACCESS::is_any_moder($arParams)
//            && !empty(array_intersect(array_keys($fieldsNew), $moderatorAccessKeys))
        ) {
            $fieldsNew = array_filter(
                $fieldsNew,
                static function ($key) use ($moderatorAccessKeys) {
                    return !in_array($key, $moderatorAccessKeys);
                },
                ARRAY_FILTER_USE_KEY
            );
        }

        $result = [];

        foreach ($fieldsNew as $key => $value) {

            if ($fieldsOld[$key] && $value == $fieldsOld[$key]) {
                continue;
            }

            $result[$key] = $value;
        }

        return $result;

    }

    private static function getModeratorAccessKeys()
    {
        return [
            'UF_ACTIVE',
            'UF_USER_ID',
            'UF_FROZEN',
            'UF_STOP_DETECTED',
            'UF_PROOF_AWAITING',
            'UF_URL_ID',
            'UF_PARENT_ID',
            'UF_DEPTH_LEVEL',
            'UF_CREATED_DATE',
        ];
    }

    /**
     * ������� ����������
     * ��� ������ ������ �������� ������ ������ � �����, ������ ���
     * ������������� �����-�� ����, � ��� ��� ����� �� ���� ��� ������������,
     * �� ������ �������� (� ��������� �����) �� ���� �����.
     *
     * �������� ��, ��� ����: ��������� �������� ������ ����� ������,
     * ������ ����� �������� ������ ������, ������������ ��� � �������� � ������� ����� ����� ���,
     * ��� ��� ������ ���������.
     *
     *
     * !!! ��������� �� ��������,
     * !!!    �� ����������:
     *
     * ���� ������� ��� �������� "��������� ������������ � �����"
     * ...��� "��������� ������������ �� ����",
     * �� ��� ����� ����������� ������������ �����-��� �����������
     *
     * �� ��� ����� �������� ������ �� �����, � ������ (����������� �����)
     * ����������� ����� �� ����� ��������� � ������� � � ������
     * ���� �� �������-�������� � ���� ����������
     *
     * @param null $id
     * @param array $arParams
     * @param bool $reverse
     * @return bool
     * @throws Exception
     */

    public static function makeActive($id = null, &$arParams = [], $reverse = 0)
    {

        if (!$id) {
            return false;
        }

        /**
         * ��������, �� ���� �� ��� ����������
         */
        $info = self::getCommentInfo($id);
        if (!$info || self::isActive($info)) {
            return false;
        }

        EVENT::call('OnBeforeCommentChangeActivity', [
            'comment_info' => &$info,
            'comment_id' => &$id,
            'ACTIVE_will_be' => &$reverse,
            'arParams' => &$arParams
        ]);

        self::updateSingle($id, ['UF_ACTIVE' => $reverse], $arParams, true);

        $info['UF_ACTIVE'] = $reverse;

        EVENT::call('OnAfterCommentChangeActivity', [
            'comment_info' => &$info,
            'comment_id' => &$id,
            'arParams' => &$arParams
        ]);

        return true;

    }

    public static function isActive($id = 0, &$commentInfo = [])
    {

        if ($id && !$commentInfo) {
            $commentInfo = self::getCommentInfo($id);
        }

        if (empty($commentInfo)) {
            return false;
        }

        /**
         * Because UF_ACTIVE may not present in array:
         * for reduce cache size we filter false keys
         */
        $ufActive = $commentInfo['UF_ACTIVE'] ?? false;
        // Some of extra fields value awaiting for approoval
        // ...if comments has not any additional field, it must be true
        $afActive = $commentInfo['AF_ACTIVE'] ?? true;

        return $ufActive && $afActive;
    }

    /**
     * �������� �������� � ���, ���� ������� ������ ������
     * ...� �������� ������ � ��
     *
     * @param null $commentId
     * @param array $arParams
     *
     * @return bool
     * @throws Exception
     */
    public static function make_delete($commentId = null, &$arParams = [])
    {

        if (!$commentId) {
            return false;
        }

        /**
         * ��������, �� ���� �� ��� ����������
         */
        $commentInfo = self::getCommentInfo($commentId);
        if (!$commentInfo || !$commentInfo['UF_URL_ID']) {
            return false;
        }


        /**
         * �������� ����� == �������� ��� �����!
         * ������� ����� ��� ������ ������������
         */

        // ���� �� ������ ������ � ���� ���
        $arParams['SKIP_CACHE'] = true;
        /**
         * ��� ����� ������ �������� ��� �����,
         * ��� ������, ��� ��������, ��� ���������� O=)
         */
        $moderator = true;
        $tree = [];

        self::getStructureOfUrlComments(
            $commentInfo['UF_URL_ID'],
            $arParams,
            $moderator,
            $tree
        );

        if (empty($tree)) {
            return false;
        }

        $commentAndSubtree = self::findSubtree($tree, $commentInfo['ID']);

        if (empty($commentAndSubtree)) {
            return false;
        }

        if ($commentAndSubtree[$commentInfo['ID']]['CHILD']) {
            self::internalDelete($commentAndSubtree[$commentInfo['ID']]['CHILD']);
        }


        EVENT::call('OnBeforeCommentDelete', [
            'comment_info' => &$commentInfo,
            'arParams' => &$arParams
        ]);

//        self::set_rows_empty([
//            ['ID' => $comment_id]
//        ]);
        self::pretendOfDeleting($commentId);

        EVENT::call('OnAfterCommentDelete', [
            'comment_info' => &$commentInfo,
            'arParams' => &$arParams
        ]);

        return true;

    }

    /**
     * @param string $urlId
     * @param array $arParams
     * @param bool $moderator
     * @param array $result
     *
     * @throws Exception
     */
    public static function getStructureOfUrlComments(&$urlId = '', &$arParams = [], &$moderator = false, &$result = [])
    {

        if (!$urlId || !$arParams || empty($arParams)) {
            throw new Exception('01: arParams is empty');
        }

        if ($arParams['SKIP_CACHE']) {
            $cacheFlagPrev = $_SESSION['SESS_CLEAR_CACHE'] ?? 'N';
            $_SESSION['SESS_CLEAR_CACHE'] = 'Y';
        }

        $rawList = self::loadRawTreeByUrlId($urlId);

        if ($arParams['SKIP_CACHE']) {
            $_SESSION['SESS_CLEAR_CACHE'] = $cacheFlagPrev;
        }

        if (!empty($rawList)) {
            $arParams['moderator'] = $moderator;
            self::get_tree_from_list($rawList, $result, $arParams);
        }

    }

    /**
     *
     * ���� ������� � ��������:
     * https://burlaka.studio/upload/realcommenter/magic_parsing.png
     *
     * �� ������� ����� � �������� �������� �� ��� �����,
     * ������ ����� ��������� �� ����, ��� ��-����� ��������� � ��������.
     *
     * ��� ��� left_margin
     * �������� ��������� �������������� � ������ � ��������� ��� �������������� ������� � �������� ����
     *
     * @param array $raw_list
     * @param array $result
     * @param array $arParams
     * @param int $start_pos
     * @param int $current_level
     *
     * @return int
     */
    private static function get_tree_from_list(&$raw_list = [], &$result = [], &$arParams = [], $start_pos = 0, $current_level = 1)
    {

        $local_level = $result;
        $local_points = [];

        for ($s = $start_pos, $sMax = count($raw_list); $s < $sMax; $s++) {

            $o = $raw_list[$s];

            //������ �����������
            $el_level = (int)$o['UF_DEPTH_LEVEL'];

            if ($el_level === $current_level) {

                if (
                    $arParams['moderator'] ||
                    ($o['UF_ACTIVE'] /*&& !$o[ 'UF_FROZEN' ]*/ && !$o['UF_PROOF_AWAITING'])
                ) {

                    if ($arParams['itape'] && $o['ID'] == $arParams['itape']) {
                        $o['hot_line'] = true;
                    }

                    /**
                     * ���� �� ���� � � �������� �� ������ ������ ��� ��������� �����
                     */
                    if ($o['UF_PARENT_ID']) {

                        /**
                         * �������� ��� ����������� ���� ���.
                         * ��� ����� �� ��, �������� ���� �������� ���� �� ���������,
                         * � ��� ������� �� ���������
                         */
                        if ($local_level[$o['UF_PARENT_ID']]) {
                            $local_level[$o['UF_PARENT_ID']]['CHILD'][$o['ID']]['INFO'] = $o;

                            /**
                             * ��������� ����� � ������������, �� ������ ������� itape-�������� �� ���� ������
                             */
                            if ($o['hot_line']) {
                                $local_level[$o['UF_PARENT_ID']]['INFO']['FOUND_BY_ITAPE_INSIDE'] = true;
                            }

                            /**
                             * ������ �����, �������� �� ������ ���������� ������������ ������
                             * ! COMM_STAT � ������ ������������ ��� ����� �����, ���� �������
                             */
                            $local_level[$o['UF_PARENT_ID']]['INFO']['COMM_STAT'] =
                                intval($local_level[$o['UF_PARENT_ID']]['INFO']['COMM_STAT']) + 1;

                            /**
                             * ���� ������ ����������� ��������� ��� ����������� "������",
                             * ������� �� ���� �������.
                             *
                             * ���� ����� �� �����������, ���� ������ ������ �����������
                             */

                            if (
                                $arParams['COLLAPSE_BRANCH']
                                && $o['UF_DEPTH_LEVEL'] >= $arParams['COLLAPSE_BRANCH']
                            ) {
                                if (TOOLS::isDateFresh($o['UF_CREATED_DATE'])) {
                                    $local_level[$o['UF_PARENT_ID']]['INFO']['FRESH_IN_CHILDREN'] = true;
                                }
                            }

                            $local_points[$o['ID']] = &$local_level[$o['UF_PARENT_ID']]['CHILD'][$o['ID']];

                        }

                    } else {

                        /**
                         * ��������� ����� � ������������, �� ������ ������� itape-�������� �� ���� ������
                         */
                        $local_level[$o['ID']] = [
                            'INFO' => $o
                        ];

                        $local_points[$o['ID']] = &$local_level[$o['ID']];
                    }
                }

            } else if ($el_level > $current_level) {

                //������� �������
                $s = self::get_tree_from_list(
                    $raw_list,
                    $local_points,
                    $arParams,
                    $s,
                    $el_level
                );

                /**
                 * ����� ���� �����,
                 * ���� ��� ����� ���������� itape-�������� � �� ���, �����, �� ������, �
                 * ���� �� ����� ����� ����� ������ ������ FOUND_BY_ITAPE_INSIDE.
                 *
                 * ����� ��� ������� �� ������ ��
                 */

                foreach ($local_points as $p_id => $p_tree) {
                    if (
                        // ������ ������ ��� ��������� ������ ������ ����� itape �����������
                        $p_tree['INFO']['FOUND_BY_ITAPE_INSIDE'] &&
                        // ...� � ���� ��� �������, ����������� ������ �� ���� ���� ��
                        $p_tree['INFO']['UF_PARENT_ID'] &&
                        $local_level[$p_tree['INFO']['UF_PARENT_ID']]
                    ) {
                        $local_level[$p_tree['INFO']['UF_PARENT_ID']]['INFO']['FOUND_BY_ITAPE_INSIDE'] = true;
                    }

                    /**
                     * ...���������, ������ ������ - �������� ���������� �� ����������� � �����
                     */
                    if (
                        $p_tree['INFO']['UF_PARENT_ID']
                        && $p_tree['INFO']['COMM_STAT']
                        && $local_level[$p_tree['INFO']['UF_PARENT_ID']]
                    ) {

                        $local_level[$p_tree['INFO']['UF_PARENT_ID']]['INFO']['COMM_STAT'] =
                            (int)$local_level[$p_tree['INFO']['UF_PARENT_ID']]['INFO']['COMM_STAT']
                            + (int)$p_tree['INFO']['COMM_STAT'];
                    }

                }

            } else {
                /**
                 * ���� � ���� �� ������ ��
                 * �����, � ��� ��������� ����������, ��� ����� ������� �� ������ ������
                 */
                break;
            }

        }

        $result = $local_level;
        return $s;
    }

    public static function findSubtree(&$tree = [], &$commentId = null)
    {
        $result = [];

        if (!empty($tree) && $commentId) {
            foreach ($tree as $nodeId => $sub) {
                if ((int)$nodeId === (int)$commentId) {
                    $result = [$nodeId => &$sub];
                    break;
                }

                if ($sub['CHILD']) {
                    $foundInSub = self::findSubtree($sub['CHILD'], $commentId);
                    if (!empty($foundInSub)) {
                        $result = $foundInSub;
                        break;
                    }
                }
            }
        }

        return $result;
    }

    protected static function internalDelete(&$subTree = [])
    {

        if (empty($subTree)) {
            return;
        }

        foreach ($subTree as $node) {
            if (!$node['INFO']['ID']) {
                continue;
            }

            if (!empty($node['CHILD'])) {
                self::internalDelete($node['CHILD']);
            }

            self::pretendOfDeleting($node['INFO']['ID']);
        }
    }

    protected static function pretendOfDeleting($id = null)
    {
        if (!$id) {
            return;
        }

        /**
         * ����� �� ������ ������ �����������, �� � ������ (��������)
         * ��� ������ �������� �����, ���� ��� ��� (������� � ���� ����������)
         */
        AdditionalFieldsValues::deleteByCommentId($id);

        self::set_rows_empty([
            ['ID' => $id]
        ]);

    }

    /**
     * ��� ����� ������� ������ ������������.
     * ... ���� ���� ���� ����� � ���������� (����������)
     * ...���� �������� ����������� ����
     *
     * �������:
     *      - ����� ������� ��������� �������� (��������� ����������� ������������ comment_id)
     *      ��� ���������� �������� �����, ����� � ����-�� ����� �������� ���� �����������
     *      � ���� �� ����������� �� ���������, ������� ���� ����� � ������ �����
     *          == ���� ������, ������������� � �������� ����� ����� �����, ��-�����, �� ����� ��� �������
     *      - ��� ������� �� ���������, � � ���������� �������� �� ������� ����� � � �� ���� � ������
     *      - ��� ������� �� ���������� ����, ������� �� ��������� �����������
     *      (� ���� ������������ GET-�������� itape). �����, ���� ������� �������
     *      � � ���� �� ���� �����������, ��� �������� �� ����, ��� ����� � �����������
     *
     * @param array $arParams
     * @param $url_id
     * @param $moderator
     *
     * @return array
     * @throws Exception
     */
    public static function getInsideRecursively(&$url_id = '', &$arParams = [], $moderator = false)
    {

        $result = [];
        self::getStructureOfUrlComments($url_id, $arParams, $moderator, $result);

        if (empty($result)) {
            return [];
        }

        /**
         * ��������� �1
         *
         * ���� ��� ����� ������ ���-���� ������ � ������ ����� � ��������� ����������
         * ������ � �����
         */
        if ($arParams['NODE_ID']) {
            return self::findSubtree($result, $arParams['NODE_ID']);
        }

        /**
         * ��������� �2
         *
         * ������� ����������. ����� � ����� �����
         */

        /**
         * ����������� ����������
         */
        $sortAndFilterSetId = $arParams['SORT_SET_ID'] ?? null;
        $sortAndFilterRuleCode = $arParams['ISORT'] ?? '';

        if ($sortAndFilterSetId && $sortAndFilterRuleCode) {
            SortPanelsConditionsHelper::processTreeBySortAndFilters(
                $result,
                $sortAndFilterSetId,
                $sortAndFilterRuleCode
            );

            if (empty($result)) {
                return [];
            }

        } else if ($arParams['REVERSE_ORDER']) {
            $result = array_reverse($result, true);
        }

        /**
         * ���������� � ��� �������� � ��� ������:
         *      � ��������� ������
         *      � ���������� ����������
         *
         * �����, ��� ��������� ������, � ��� ���������� �������� ������� ��������:
         *      � ������ ����� ������� ����� �������� ��� ������ ������� ���������
         *      � ������ ����� ��������� � ������� ������� �����
         */

        $ipage = (int)($arParams['IPAGE'] ?? 0) ?: (int)TOOLS::request_get('IPAGE') ?: 1;

        /**
         * ��������� ����������:
         *      LIMIT_START - ���� ���������� ����� �� � ��������� ������
         *      USE_PAGE_NAV � �������� �� �� ���������� ����������
         *      LIMIT_EVERY_NEXT � ������ ������ ������������ ����� ��� ������ ������� �� ����� ������� ����������� ����������
         */
        if ($arParams['USE_PAGE_NAV'] && $arParams['LIMIT_EVERY_NEXT']) {

            /**
             * � ������ ���� ���� ����� � ���� ���� ����
             * �������, ��� ����� �� ������� ����� ������
             */
            $limit_from = ($ipage - 1) * $arParams['LIMIT_EVERY_NEXT'];
            $limit_portion = $arParams['LIMIT_EVERY_NEXT'];

        } else {

            /**
             * �������, ����� �������.
             * �������, ��� ��� ��� ���� �����: ����� ���� � ����� ������ ����
             */
            if ($ipage <= 1) {
                $limit_from = 0;
            } else {
                $limit_from = $arParams['LIMIT_START'] + ($ipage - 2) * $arParams['LIMIT_EVERY_NEXT'];
            }

            /**
             * ���� ���������� ����, ���� ��� ���� ������ �� "�������� �������" - �� �� ������
             */
            if ($arParams['NAV_ACTION'] === '*') {
                $limit_portion = count(array_keys($result)) - $limit_from;
            } else {
                $limit_portion = (!$ipage || $ipage === 1) ? $arParams['LIMIT_START'] : $arParams['LIMIT_EVERY_NEXT'];
            }

        }

        /**
         * ��������� �3
         *
         * � ����� �� ��������� ����������� ��������� ��� ���, � ���������� itape
         *      1. ��� ����� �����, � ����� ����� ��� ���� ���� (� ��� ��)
         *      2. ��������������� ������� �� ����������� �������� ���, ���� ���� ����� �� �������
         *
         * ������ ������ ����� �� ���� � ���� ����� ��� - ��� ������� �������� ������ ...
         *      [INFO][hot_line] == true // ��������������� ������
         *      ...���� [FOUND_BY_ITAPE_INSIDE] // ������ ���� ������ ������ ������
         *
         * ��� ���, ���� ���� �������� �� ���� �������� ����� �� ������� ����� ������.
         * �� ��� ����� ������ �� ����� ����� �������������, ���� ����� ��� ����������.
         * ...��� ���������� �������, ������ ��� ������ ��� ������� ����� ��������� � ����������
         *
         * (!!!) ...� ���������� �� ��� ������ ���� � ����� ����� ���� ������ ����������
         * � ���� �������� ���� �� �������� � ����, ������ ����� ���������� �� �������.
         *      (���������� �������� �� ����� �� ��������� ��� � ����� ��� ���������� ����, ���� �����)
         *
         * ���� ��������� ������ � ����� ������� ����� ������ �������,
         * ���� ������� ����������� �� � ������� �����
         *
         * ���� ���������� ���������� � ������, ����� ����� ����������� �������� �������
         */

        //��� ����� ���� ���������, ������ ��� ��� ������� � id-��� �����

        $itape_pos = 0;
        $itape_found = false;

        if ($arParams['itape'] && $limit_portion) {

            foreach ($result as $r_node) {
                if (
                    $r_node['INFO']['hot_line'] ||
                    $r_node['INFO']['FOUND_BY_ITAPE_INSIDE']
                ) {
                    $itape_found = true;
                    break;
                }

                $itape_pos++;
            }

            if ($itape_found) {

                $less_than = ($itape_pos < $limit_from);
                $more_than = ($itape_pos > ($limit_from + $limit_portion));

                if (
                    $less_than
                    || $more_than
                ) {

                    if ($arParams['USE_PAGE_NAV']) {
                        /**
                         * ���� ���������� ���������� - ������ ����� ����������� ��������.
                         * ��� ��������� ������� �������
                         */
                        $ipage = (int)ceil(($itape_pos + 1) / $limit_portion);
                        $limit_from = ($ipage - 1) * $limit_portion;

                    } else {

                        /**
                         * ���� ��������� ������ � (!) ����� ������ � ���:
                         * ����� �������, ��� $_GET �������� itape ����� �� ����� ��� ������ ������� ������,
                         * ��� ����� �������� � ���
                         *
                         * � ��� ���� ������ ������ ����� ������ �����, ���� ���������� ����� � ���� ������������
                         */

                        $limit_portion = max($itape_pos + 1, $limit_portion);

                        /**
                         * ����� ���������� ����� ������.
                         * ���� ��������� ������� ����� ��������� ����������� � ��� ����������� ������
                         */

                        if ($limit_portion <= $arParams['LIMIT_START']) {
                            $ipage = 1;
                        } else {
                            $ipage = 1 + ceil(($limit_portion - $arParams['LIMIT_START']) / $arParams['LIMIT_EVERY_NEXT']);
                        }

                        $limit_from = $arParams['LIMIT_START'] + ($ipage - 1) * $arParams['LIMIT_EVERY_NEXT'];

                    }
                }
            } else {
                /**
                 * ��� ��������� � ����� ����������, �� � ������ �� ����.
                 * ����� �� ������ ���
                 */
                LocalRedirect(
                    TOOLS::normalize_url(['itape'], $arParams['URL']),
                    true,
                    '301 (Moved Permanently)'
                );
            }

        }

        try {
            $arParams['NAV'] = PAGINATION::calculate_values($result, $arParams, $ipage);
        } catch (RuntimeException $e) {
            LocalRedirect(
                TOOLS::normalize_url(['ipage'], $arParams['URL'], 'isort'),
                true,
                '301 (Moved Permanently)'
            );
        }

        /**
         * ���� ��� ����� ����������� �������������,
         * ������ ��� ������� ����� (������ ��� ���� � ����� �������)
         */

        if (MicrodataReview::inUse($arParams)) {
            $firstNodesMass = array_keys($result);

            $firstNodesForReview = [];

            foreach ($firstNodesMass as $nodePos) {
                $nodeInfo = $result[$nodePos]['INFO'] ?? null;
                if (!$nodeInfo || !$nodeInfo['UF_ACTIVE']) {
                    continue;
                }

                $reviewText = $nodeInfo['UF_COMMENT'] ?? null;
                if (!$reviewText && $nodeInfo['AF_VALUES']) {
                    $groupId = $nodeInfo['COMMENT_GROUP_ID'] ?? $arParams['TALK_GROUP_ID'];
                    if ($addiFields = AdditionalFields::getFieldsByGroup($groupId)) {

                        $reviewParts = array_reduce(
                            $addiFields,
                            static function ($carry, $fieldData) use ($nodeInfo) {
                                if (
                                    $fieldData['UF_TYPE'] === 'text'
                                    && $nodeInfo['AF_VALUES'][$fieldData['ID']]
                                ) {
                                    $carry[] = $fieldData['UF_NAME'] . ': ' . $nodeInfo['AF_VALUES'][$fieldData['ID']];
                                }
                                return $carry;
                            }, []);

                        $reviewText = implode('. ', $reviewParts);
                    }
                }

                if (!$reviewText) {
                    continue;
                }

                $firstNodesForReview[] = [
                    'UF_SIGNATURE' => $nodeInfo['UF_SIGNATURE'] ?? 'Anonimus',
                    'REVIEW_TEXT' => $reviewText
                ];
            }

            self::nodesCollector($firstNodesForReview);
        }

        if ($limit_portion) {

            $first_nodes_mass = array_keys($result);

            /**
             * ����� ������ �������������.
             * �������� ������ �� ���������� �� ������������ ������,
             * ������ �� ����� ������ ��� � �������
             */

            if ($limit_portion >= count($first_nodes_mass)) {
                // ������ ������ �������� - ���� �� ���� ���� �� ������ (��� ������ => ���� ������� �������� ����)

                $limit_portion = count($first_nodes_mass);
                $limit_from = 0;

            } else if ($limit_from + $limit_portion > count($first_nodes_mass)) {
                /**
                 * ���� ������� ��� ���� ����, ��� ��������� � �������
                 * 0 1 2 3 4 5 6 = count 7
                 *
                 * 5 + 3 > 7
                 * 7 - 3 = 4  => portion 3 from 4 => 4,5,6
                 *
                 */

                $limit_from = count($first_nodes_mass) - $limit_portion;
            }

            $limit_target_nodes = array_splice($first_nodes_mass, $limit_from, $limit_portion);
            $result2parse = $result;
            $result = [];

            foreach ($limit_target_nodes as $node_id) {
                $result[$node_id] = $result2parse[$node_id];
            }

        }

        return $result;

    }

    public static function nodesCollector($newPortion = null)
    {
        static $nodes = [];
        if ($newPortion) {
            $nodes = array_merge($nodes, $newPortion);
        }

        return $nodes;
    }

    public static function publicTreeRecursively(&$insideTree = [], &$arParams = [])
    {

        if (!$arParams) {
            return '';
        }

        if (empty($insideTree)) {

            $sortAndFilterSetId = $arParams['SORT_SET_ID'] ?? null;
            $sortAndFilterRuleCode = $arParams['ISORT'] ?? '';

            if ($sortAndFilterSetId && $sortAndFilterRuleCode) {
                return Burn::burnSortAndFilterEmptyResult($arParams);
            }

            return '';
        }

        $result = [];

        foreach ($insideTree as $node) {

            /**
             * ������� ������ id - ���� �� ��� ������� � ��, � ����������� �� ������
             *
             * ������ ������ � ������� arParams, ���� ����� ������ �������� ������ ������,
             * ��� ����������� ��������� ������ ��������������
             */

            $commentActive = self::isActive(0, $node['INFO']);
            if (!$commentActive && !GRANT_AND_ACCESS::is_any_moder($arParams)) {
                continue;
            }

            /**
             * ���� � ��� � ��������� ����� ����������� ����� � ����������� ������
             * � � ������ � ���� �������, ����� ��������:
             *      - ���� ��� �������� (� ��� �������� COMM_STAT - ��������� ������������ ��� ���),
             *      ��������� ����� �� ������������� � ���������
             *
             * (!!!) � �����, ������ � ��������� �������, ����� �� ������ �����������.
             * ���� ����� �� ����������
             */

            /**
             * ��� �� ����� �������� � ��������.
             * � �������� �� ������ �������� � ������� ��������.
             *
             * ����� �� ������, ����� ���� �� ���������� ����� ������� � ������� ������.
             * ��������: ����� ��� ����������, ����� ������ �� ���� ������������� �� �����������.
             *
             * ���� ��������� �� ���� ������ � ���, ��� ���-�� �� � ���������,
             * ������� ���������� �������� �� BRANCH_IN_SPECIAL_CASE
             *
             * ���� �����-�� ���� �� ���� ��������� ������� � ���� ������,
             * ����� ��������� ������������� ������ (DEPTH_LEVEL) ����, �� ������� ������ ����� ������
             *
             * ���� ����, ������ ������� ����� ���� ����� ���� �������,
             * �� �������� � ���� ����� ���������.
             *
             * ���� ������� �� ��� �� ������� ��� �� (������� �� �����), �������� �������
             */

            $_empty = [];
            if (
                self::in_special_case(0, $_empty, $node['INFO'])
                || self::frozen(0, $node['INFO'])
            ) {
                $arParams['BRANCH_IN_SPECIAL_CASE'] = $node['INFO']['UF_DEPTH_LEVEL'];
            } else {
                if (
                    $arParams['BRANCH_IN_SPECIAL_CASE']
                    && $node['INFO']['UF_DEPTH_LEVEL'] <= $arParams['BRANCH_IN_SPECIAL_CASE']
                ) {
                    $arParams['BRANCH_IN_SPECIAL_CASE'] = 0;
                }
            }

            $commentBranches = '';
            $expandBlock = '';

            if (
                $arParams['COLLAPSE_BRANCH']
                && $node['INFO']['UF_DEPTH_LEVEL'] + 1 >= $arParams['COLLAPSE_BRANCH']
                && $node['INFO']['COMM_STAT']
                && !$node['INFO']['FRESH_IN_CHILDREN']
                && !$node['INFO']['FOUND_BY_ITAPE_INSIDE']
            ) {

                $expandBlock = sprintf(
                    '<ins>%s %s <strong data-value="%s"></strong></ins>',
                    Loc::getMessage('ITAPE_more_to_expand'),
                    $node['INFO']['COMM_STAT'],
                    Loc::getMessage('ITAPE_expand_title')
                );

            } else if ($node['CHILD']) {
                $commentBranches = self::publicTreeRecursively($node['CHILD'], $arParams);

                /**
                 * (!!!)
                 * ������ ���� (����� ��������� ����� � �����)
                 * ����� ������ ��� �������������� �������� - � BRANCH_IN_SPECIAL_CASE
                 * (��������: ��������� �� <= � <)
                 *
                 * ������ ��� � ����� ����� � �������, ��� � �������� ���������� ���� ��
                 * ...� ��������� �� ������� ���������� � �� �������
                 * (������ ��� arParams � ����������� ����� ���������� �� ������).
                 */

                if (
                    $arParams['BRANCH_IN_SPECIAL_CASE']
                    && $node['INFO']['UF_DEPTH_LEVEL'] < $arParams['BRANCH_IN_SPECIAL_CASE']
                ) {
                    $arParams['BRANCH_IN_SPECIAL_CASE'] = 0;
                }

            }

            $commentNewLink = '';
            /**
             * ����� �� ������� ����������� ��� ������ ������������
             */
            if (
                GRANT_AND_ACCESS::may_comment($arParams) &&
                // !!! ��� �� ������� ������ ��������, ������ ��� ������� ��� ����� �������� ������, � �� �����
                GRANT_AND_ACCESS::have_access_by_special_case_of_comment(
                    $node['INFO']['ID'],
                    $arParams,
                    $node['INFO']
                ) &&
                !GRANT_AND_ACCESS::restrictedDepth(
                    $arParams,
                    $node['INFO']['UF_DEPTH_LEVEL']
                ) &&
                // ���������� ����� �� �����, �� ��������� ���������� �� ������ ������������
                // ...� ���������� ���� �������������, ���� �� ������� �� ������
                !GRANT_AND_ACCESS::restricted_by_auth_limit($arParams) &&
                !Sanctions::restrictedUser()
            ) {
                $commentNewLink = sprintf(
                    '<span>%s</span>',
                    self::get_comment_link_ancor($arParams, 'inside')
                );
            }

            /**
             * ���� ����� ������� ����� ������������� ����������,
             * ��������: �������� � ��������� ����� �������� ������ ���� �����������
             * ...� � ��������� ���� �� �������
             */
            $showEditCommentLikeAuthorLink = false;

            if (
                $node['INFO']['UF_USER_ID']
                && GRANT_AND_ACCESS::may_edit_comment_like_author(
                    $node['INFO']['UF_USER_ID'],
                    $node['INFO']['UF_CREATED_DATE']
                )
            ) {
                $showEditCommentLikeAuthorLink = sprintf(
                    '<abbr data-to-edit="1">%s</abbr>',
                    Loc::getMessage('ITAPE_edit_title')
                );

            }

            $commentFrozen = self::frozen(0, $node['INFO']);
            $commentUnmoderated = self::isProofAwaiting(0, $node['INFO']);
            $commentFresh = TOOLS::isDateFresh($node['INFO']['UF_CREATED_DATE']);

            $commentStructTpl = HTML_TEMPLATER::get('comment_struct', $arParams);

            if ($arParams['BRANCH_IN_SPECIAL_CASE']) {
                $commentNewLink = '';
            }

            // ��� ���������� ����������� ����� � ����, ����������, ... �����
            if (self::in_special_case(0, $_empty, $node['INFO'])) {
                $expandBlock = '';
            }

            $search = [
                '#DISABLED#' => (!$commentActive) ? '_disabled' : '',
                '#FROZEN#' => ($commentFrozen) ? '_frozen' : '',
                '#UNMODERATED#' => ($commentUnmoderated) ? '_proof_awaiting' : '',
                '#ID#' => $node['INFO']['ID'],
                '#FRESH_CASE#' => ($commentFresh) ? '_fresh' : '',
                '#FOUND_BY_URL_ANCOR#' => ($node['INFO']['hot_line']) ? '_found' : '',
                '#COMMENT_HEADER#' => Burn::burnCommentHeader($node['INFO'], $arParams),
                '#COMMENT_ASIDE#' => Burn::burnCommentAside($node['INFO'], $arParams),
                '#COMMENT_TEXT#' => self::compileCommentText($node['INFO'], $arParams),
                '#COMMENT_UPLOADS#' => Burn::burnCommentUploads($node['INFO'], $arParams),
                '#EXPAND_BLOCK#' => $expandBlock,
                '#COMMENT_BRANCHES#' => $commentBranches,
                '#ANSWER_LINK#' => $commentNewLink,
                '#EDIT_LINK_FOR_AUTHOR#' => $showEditCommentLikeAuthorLink,
                '#PROOF_AWAITING_TITLE#' => Burn::proofAwaitingTitle($node['INFO'], $arParams),
                /* schema.org */
//                '#SCHEMA_ORG_WRAPPER#' => Burn::schemaOrgWrapper('open', $node['INFO'], $arParams),
//                '#/SCHEMA_ORG_WRAPPER#' => Burn::schemaOrgWrapper('close', $node['INFO'], $arParams),
            ];

            EVENT::call('OnBeforeCommentStructBurn', [
                'commentStructTpl' => &$commentStructTpl,
                'keyValuesForReplace' => &$search,
                'arParams' => $arParams,
                'nodeInfo' => $node['INFO']
            ]);

            $commentNode = str_replace(
                array_keys($search),
                array_values($search),
                $commentStructTpl
            );

            $result[] = $commentNode;
        }

        return implode('', $result);
    }

    /**
     * ����������� ����� ������� � ���� ������:
     *      - �� ���������
     *      - �� �����������
     *      - �� �� ������ �����������, ������ ������ ������� �� ���������� ����������
     *
     * �� �������������� ��� ������������� ������ ����������
     * ������� ������������ ������ (�� �������, �����������)
     *
     * @param int $id // ������� ���� id � ��������� �� ������� ���� (����� ������� ������ � ��)
     * @param array $arParams
     * @param array $comment_info // ...���� ������ � ����� (��������, �� ���� ��������� ����� ������������ �� �������)
     *
     * @return bool
     */
    public static function in_special_case($id = 0, &$arParams = [], &$comment_info = [])
    {

        // ����� ���� ��� ��� ���������� ���������
        if ($id && empty($comment_info)) {
            $comment_info = self::getCommentInfo($id);
        }

        if (!$id && empty($comment_info)) {
            /**
             * !!! ����� �� �������� � � ������ id
             * �����, �����������, ��� �������� - ����� �� ���������� ������� ���� �����������
             *
             * ����� ������ false
             * �� ��� ������� �� ������:
             *      � ������� �� ����������� � ������� ������?
             *      � "���, �� �������"
             */

            return false;
        }

        if (
            !self::isActive($id, $comment_info)
            //|| self::is_frozen( $id, $comment_info ) // ����������� - ��� ���� ������ �������������, � �� �������� �����
            || self::isProofAwaiting($id, $comment_info)
        ) {
            return true;
        }

        return false;

    }

    public static function isProofAwaiting($id = 0, &$commentInfo = [])
    {

        if ($id && !$commentInfo) {
            $commentInfo = self::getCommentInfo($id);
        }

        if (empty($commentInfo)) {
            return false;
        }

        /**
         * Because UF_PROOF_AWAITING may not present in array:
         * for reduce cache size we filter false keys
         */
        $ufProofAwaiting = $commentInfo['UF_PROOF_AWAITING'] ?? null;
        // Some of extra fields value awaiting for approoval
        $afProofAwaiting = $commentInfo['AF_PROOF_AWAITING'] ?? null;

        return $ufProofAwaiting || $afProofAwaiting;

    }

    public static function frozen($id = 0, &$info = [])
    {

        if ($id && !$info) {
            $info = self::getCommentInfo($id);
        }

        if (empty($info)) {
            return false;
        }

        return $info['UF_FROZEN'] ?? null;

    }

    public static function get_comment_link_ancor(&$arParams = [], $link_type = 'inside')
    {

        if (!$link_type) {
            return '';
        }


        if ($arParams && $arParams['lang_add_inside_comment']) {
            return $arParams['lang_add_inside_comment'];
        }

        $link_type = strtoupper($link_type);
        return Loc::getMessage('ITAPE_' . $link_type . '_COMMENT_LINK_ANCOR');

    }

    public static function compileCommentText(&$commentInfo = null, $arParams = [])
    {
        $result = '';

        if (!empty($commentInfo)) {

            $result = (isset($commentInfo['AF_VALUES']) && !empty($commentInfo['AF_VALUES']))
                ? Burn::burn_addi_fields_aside($commentInfo, $arParams)
                : Burn::burn_comment_text($commentInfo, $arParams);
        }

        $simplifyMode = $arParams['SIMPLIFY_TO_TEXT'] ?? false;
        if ($simplifyMode) {
            $result = \TxtToHTML(\HTMLToTxt($result));

            $search = ["&lt;", "&gt;", "&quot;", "&#39;", "&#37;", "&#41;", "&#40;", "&#43;"];
            $replace = ["<", ">", "\"", "'", "%", ")", "(", "+"];
            $result = str_replace($search, $replace, $result);
        }

        return $result;
    }

    /**
     * � ��� �������� ������� ��������������� ���� UF_URL_ID,
     * ������� ���������� ������� �������������� ����������, ��� ����������� �� ������ �����������
     *
     * ����� ������� � ����� ����� �������� ����� ��� ����������� �� ����������� ��� ����
     *
     * � ��� ������ ��� ������ ������
     * ...���������� ��� ����������, ��������, �������������� ����� ��������
     *
     * @param int $urlId
     * @param bool $skipCache
     *
     * @return array|bool
     * @deprecated
     */
    private static function load_raw_tree_by_url_id(&$urlId = 0, $skipCache = false)
    {

        if (!$urlId) {
            return [];
        }

        $tree_raw = [];

        $cache_obj = CACHE::getCacheObj();
        $cache_key = CACHE::get_url_key_for_comments($urlId);
        $cache_TTL = CACHE::getTtl();

        /**
         * ���� � ��� ���������� ������.
         *
         * ���� ����� � ��������� ���������� ����� ������� ���������� ����������
         * (� ��� ��������� ����� � ����� ������� �����)
         * ...������ ��� ���� ������� ������ �������� ��� ������� ����� � ������� �������.
         *
         * ���������� ���� ��������� ����� �� ����� ������� �����
         * ... �� ��� ���� � ������
         */

        if (!$skipCache) {
            if ($cache_obj->initCache($cache_TTL, $cache_key, TOOLS::getModuleName())) {
                // ���� �� ���
                $tree_raw = $cache_obj->getVars();
            }
        }

        if (empty($tree_raw)) {

            CTimeZone::Disable();
            $tree_raw = self::getList_EX(
                [
                    'UF_URL_ID' => $urlId
                ],
                [
                    /**
                     * �� ����� �����������
                     */
                    'UF_DEPTH_LEVEL' => 'ASC',

                    /**
                     * �� ������������ ����������
                     * (��� ��� ���� - ���������� ����� ����������� ���� ����� ID,
                     * ��� ���������� �����
                     */
                    'UF_PARENT_ID' => 'ASC',

                    /**
                     * �� ���� == ����� ���� ����, ����� ������� � �����
                     */
                    'UF_CREATED_DATE' => 'ASC',

                    /**
                     * ��������� �����
                     */
                    'ID' => 'ASC'
                ]
            );
            CTimeZone::Enable();

            /**
             * �������� � ������� ��� � ����� �������� � int-�
             */
            foreach ($tree_raw as $row_pos => & $row) {
                TOOLS::normalizeValues($row, [
                    'UF_COMMENT',
                    'UF_SIGNATURE',
                    'UF_EMAIL',
                    'UF_CREATED_DATE',
                    'UF_UPLOADS'
                ]);
            }

            /**
             * �������� ��� � ������ ��������, ���� �������� �� ���
             */
            foreach ($tree_raw as $row_pos => & $row) {
                $row = array_filter($row);
                PARSER::processMsgForPublish($row['UF_COMMENT']);
            }

            if ($cache_obj->startDataCache($cache_TTL, $cache_key)) {
                // ���� � ��
                $cache_obj->endDataCache($tree_raw);
            }
        }

        return $tree_raw;

    }

//	public static function get_form_title( &$arParams= [] ) {
//
//		if ( $arParams && $arParams[ 'lang_comment_form_title' ] ) {
//			return $arParams[ 'lang_comment_form_title' ];
//		}
//
//		return \Bitrix\Main\Localization\Loc::getMessage( 'ITAPE_LANG_COMMENT_FORM_TITLE' );
//
//	}
//
//	public static function get_send_btn_ancor( &$arParams= [] ) {
//
//		if ( $arParams && $arParams[ 'lang_send_comment' ] ) {
//			return $arParams[ 'lang_send_comment' ];
//		}
//
//		return \Bitrix\Main\Localization\Loc::getMessage( 'ITAPE_LANG_COMMENT_FORM_SEND' );
//
//	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit