Полный цикл в digital

Создание простого компонента в d7 для Highload-блоков

Готовый код можно скачать в моем репозитории на GitFlic.

Простой компонент, который одновременно поддерживает работу с инфоблокам и hl-блокам. В данном случае HL-блок выступает в качестве справочника обычному инфоблоку.

.description.php

.description.php<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
$arComponentDescription = array(
    // название компонента
    'NAME' => 'Вывод оборудования (кассовые аппараты) для продажи',
    // описание компонента
    'DESCRIPTION' => 'Выводит списком кассовые аппараты на странице',
    // путь к иконке компонента относительно папки компонента
    'ICON' => '/images/eaddlist.gif',
    // показывать кнопку очистки кеша
    'CACHE_PATH' => 'Y',
    // порядок сортировки в визуальном редакторе
    'SORT' => 30,
    // признак комплексного компонента
    'COMPLEX' => 'N',
    // расположение компонента в визуальном редакторе
    "PATH" => array(
        "ID" => "likee",
        "NAME" => "Лайки",
    ),
);

.parameters.php

.parameters.php<?
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
// пространства имен highloadblock
use Bitrix\Highloadblock\HighloadBlockTable;
// проверяем установку модуля «Информационные блоки»
if (!CModule::IncludeModule('iblock')) {
    return;
}
// проверяем установку модуля «Highload блоки»
if (!CModule::includeModule('highloadblock')) {
    return;
}
/*******************************/
// Инфоблоки                   //
/*******************************/
// получаем массив всех типов инфоблоков для возможности выбора
$arIBlockType = CIBlockParameters::GetIBlockTypes();
// пустой массив для вывода 
$arInfoBlocks = array();
// выбираем активные инфоблоки
$arFilterInfoBlocks = array('ACTIVE' => 'Y');
// сортируем по возрастанию поля сортировка
$arOrderInfoBlocks = array('SORT' => 'ASC');
// если уже выбран тип инфоблока, выбираем инфоблоки только этого типа
if (!empty($arCurrentValues['IBLOCK_TYPE'])) {
    $arFilterInfoBlocks['TYPE'] = $arCurrentValues['IBLOCK_TYPE'];
}
// метод выборки информационных блоков
$rsIBlock = CIBlock::GetList($arOrderInfoBlocks, $arFilterInfoBlocks);
// перебираем и выводим в адмику доступные информационные блоки
while ($obIBlock = $rsIBlock->Fetch()) {
    $arInfoBlocks[$obIBlock['ID']] = '[' . $obIBlock['ID'] . '] ' . $obIBlock['NAME'];
}
// выбираем элементы инфоблока
$arFilterElement = ['IBLOCK_ID' => $arCurrentValues['IBLOCK_ID']];
// метод выборки элементов инфоблока
$rsElement = CIBlockElement::GetList(
    array("ID" => "ASC"),
    $arFilterElement,
    false,
    false,
    array()
);
while ($obElement = $rsElement->Fetch()) {
    $arElementInfoBlocks[$obElement['ID']] = '[' . $obElement['ID'] . '] ' . $obElement['NAME'];
}
/*******************************/
// Highload блоки              //
/*******************************/
// пустой массив для вывода 
$arHlBlocksList = [];
// получаем список всех Highload блоков для возможности выбора
$hlblockIterator = HighloadBlockTable::getList();
while ($hlblock = $hlblockIterator->fetch()) {
    $arHlBlocksList[$hlblock['ID']] = '[' . $hlblock['ID'] . '] ' . $hlblock['NAME'];;
}
// получаем поля выбранного HL блока
if (!empty($arCurrentValues['HL_BLOCK'])) {
    $hlblockId = $arCurrentValues['HL_BLOCK'];
    // получаем информацию о Highload блоке
    $hlblock = HighloadBlockTable::getById($hlblockId)->fetch();
    // получаем описание сущности Highload блока
    $hlEntity = HighloadBlockTable::compileEntity($hlblock);
    // получаем список полей сущности
    $hlFields = $hlEntity->getFields();
    // наполняем список доступных полей
    foreach ($hlFields as $fieldName => $field) {
        $arHlBlocksFields[$fieldName] = $fieldName;
    }
}
// настройки компонента, формируем массив $arParams
$arComponentParameters = array(
    // основной массив с параметрами
    'PARAMETERS' => array(
        // выбор типа инфоблока
        'IBLOCK_TYPE' => array(                  // ключ массива $arParams в component.php
            'PARENT' => 'BASE',                  // название группы
            'NAME' => 'Выберите тип инфоблока',  // название параметра
            'TYPE' => 'LIST',                    // тип элемента управления, в котором будет устанавливаться параметр
            'VALUES' => $arIBlockType,           // входные значения
            'REFRESH' => 'Y',                    // перегружать настройки или нет после выбора (N/Y)
            'DEFAULT' => '',                     // значение по умолчанию
            'MULTIPLE' => 'N',                   // одиночное/множественное значение (N/Y)
        ),
        // выбор самого инфоблока
        'IBLOCK_ID' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Выберите родительский инфоблок',
            'TYPE' => 'LIST',
            'VALUES' => $arInfoBlocks,
            'REFRESH' => 'Y',
            "DEFAULT" => '',
            "ADDITIONAL_VALUES" => "Y",
        ),
        // выбор элемента инфоблока
        'ELEMENT_ID' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Выберите элемент инфоблока',
            'TYPE' => 'LIST',
            'VALUES' => $arElementInfoBlocks,
            'REFRESH' => 'Y',
            "DEFAULT" => '',
            "ADDITIONAL_VALUES" => "Y",
        ),
        // выбор типа highload блока
        'HL_BLOCK' => [
            'PARENT' => 'BASE',
            'NAME' => 'Выберите тип HL блока',
            'TYPE' => 'LIST',
            'VALUES' => $arHlBlocksList,
            'REFRESH' => 'Y',
        ],
        // выбор самого highload блока
        'HL_BLOCK_SORT' => [
            'PARENT' => 'BASE',
            'NAME' => 'Поле для сортировки',
            'TYPE' => 'LIST',
            'VALUES' => $arHlBlocksFields,
            'REFRESH' => 'N',
        ],
        // настройки кэширования
        'CACHE_TIME' => array(
            'DEFAULT' => 3600
        ),
    ),
);

class.php

class.php<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// класс для работы с языковыми файлами
use Bitrix\Main\Localization\Loc;
// класс для всех исключений в системе
use Bitrix\Main\SystemException;
// класс для загрузки необходимых файлов, классов, модулей
use Bitrix\Main\Loader;
// пространства имен highloadblock
use Bitrix\Highloadblock\HighloadBlockTable;
// основной класс, является оболочкой компонента унаследованного от CBitrixComponent
class CIblocListOborudovanie extends CBitrixComponent
{
    // выполняет основной код компонента, аналог конструктора (метод подключается автоматически)
    public function executeComponent()
    {
        try {
            // подключаем метод проверки подключения модуля «Информационные блоки»
            $this->checkModules();
            // подключаем метод подготовки массива $arResult
            $this->getResult();
        } catch (SystemException $e) {
            ShowError($e->getMessage());
        }
    }
    // подключение языковых файлов (метод подключается автоматически)
    public function onIncludeComponentLang()
    {
        Loc::loadMessages(__FILE__);
    }
    // проверяем установку модуля «Информационные блоки» (метод подключается внутри класса try...catch)
    protected function checkModules()
    {
        // если модуль информационные блоки не подключен
        if (!Loader::includeModule('iblock')) {
            // выводим сообщение в catch
            throw new SystemException(Loc::getMessage('IBLOCK_MODULE_NOT_INSTALLED'));
        }
        // если модуль highload блоки не подключен
        if (!CModule::IncludeModule('highloadblock')) {
            // выводим сообщение в catch
            throw new SystemException(Loc::getMessage('HIGHLOAD_MODULE_NOT_INSTALLED'));
        }
    }
    // обработка массива $arParams (метод подключается автоматически)
    public function onPrepareComponentParams($arParams)
    {
        // время кеширования
        if (!isset($arParams['CACHE_TIME'])) {
            $arParams['CACHE_TIME'] = 3600;
        } else {
            $arParams['CACHE_TIME'] = intval($arParams['CACHE_TIME']);
        }
        // возвращаем в метод новый массив $arParams     
        return $arParams;
    }
    // подготовка массива $arResult (метод подключается внутри класса try...catch)
    protected function getResult()
    {
        // если нет валидного кеша, получаем данные из БД
        if ($this->startResultCache()) {
            $flag = true;
            // создаем объект Query, в качестве параметра передаем объект сущности (элемент инфоблока)
            $query = new Bitrix\Main\Entity\Query(
                \Bitrix\Iblock\Elements\ElementOborudovanieapiTable::getEntity()
            );
            // выбираем что попадет в выборку
            $query->setSelect(array('ID', 'NAME', 'DETAIL_TEXT', 'DETAIL_PICTURE', 'OBORUDOVANIE_' => 'OBORUDOVANIE'))
                // ставим фильтр
                ->setFilter(array('IBLOCK_ID' => $this->arParams['IBLOCK_ID']));
            // выполняем запрос
            $result = $query->exec();
            // заполняем arResult
            while ($row = $result->fetch()) {
                // получаем данные картинки
                if (!empty($row['DETAIL_PICTURE']) && $flag) {
                    $row['DETAIL_PICTURE'] = CFile::GetFileArray($row['DETAIL_PICTURE']);
                }
                // один раз заполняем общий массив
                if ($row && $flag) {
                    $this->arResult = $row;
                    $flag = false;
                }
                // если поле оборудование заполнено
                if (!empty($row['OBORUDOVANIE_VALUE'])) {
                    // делаем выборку хайлоуд блока
                    $arHLBlock = HighloadBlockTable::getById($this->arParams['HL_BLOCK'])->fetch();
                    // инициализируем класс сущности хайлоуд блока
                    $obEntity = HighloadBlockTable::compileEntity($arHLBlock);
                    // обращаемся к DataManager
                    $strEntityDataClass = $obEntity->getDataClass();
                    // стандартный запрос getList 
                    $rsData = $strEntityDataClass::getList(array(
                        'select' => array('*'),
                        'order' => array($this->arParams['HL_BLOCK_SORT'] => 'ASC'),
                        'filter' => array('=UF_XML_ID' => $row['OBORUDOVANIE_VALUE']),
                    ));
                    // выполняем запрос
                    $array = $rsData->fetchALL();
                    // получаем данные картинки
                    $array[0]['PICTURE'] = CFile::GetFileArray($array[0]['UF_FILE']);
                    $array[0]['ITOGO'] = $array[0]['UF_PRICE_1'] + $array[0]['UF_PRICE_2'] + $array[0]['UF_PRICE_3'] + $array[0]['UF_PRICE_4'] + $array[0]['UF_PRICE_5'];
                    // заполняем arResult
                    $this->arResult['OBORUDOVANIE'][] = $array[0];
                }
            }
            // устанавливаем SEO
            $ipropElementValues = new \Bitrix\Iblock\InheritedProperty\ElementValues($this->arParams['IBLOCK_ID'], $this->arParams['ELEMENT_ID']);
            $this->arResult['SEO'] = $ipropElementValues->getValues();
            // очищаем массив
            unset($this->arResult['OBORUDOVANIE_VALUE'], $this->arResult['OBORUDOVANIE_ID'], $this->arResult['OBORUDOVANIE_IBLOCK_ELEMENT_ID'], $this->arResult['OBORUDOVANIE_IBLOCK_PROPERTY_ID']);
            // кэш не затронет весь код ниже, он будут выполняться на каждом хите, здесь работаем с другим $arResult, будут доступны только те ключи массива, которые перечислены в вызове SetResultCacheKeys()
            if (isset($this->arResult)) {
                // ключи $arResult перечисленные при вызове этого метода, будут доступны в component_epilog.php и ниже по коду, обратите внимание там будет другой $arResult
                $this->SetResultCacheKeys(
                    array(
                        'SEO'
                    )
                );
                // подключаем шаблон и сохраняем кеш
                $this->IncludeComponentTemplate();
            } else { // если выяснилось что кешировать данные не требуется, прерываем кеширование и выдаем сообщение «Страница не найдена»
                $this->AbortResultCache();
                \Bitrix\Iblock\Component\Tools::process404(
                    Loc::getMessage('PAGE_NOT_FOUND'),
                    true,
                    true
                );
            }
        }
    }
}

template.php

template.php<? if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die(); ?>
<div class="oborudovanie-head">
    <div class="container">
        <div class="oborudovanie-head__inner">
            <div class="oborudovanie-head__content">
                <h1><?= $arResult['SEO']['ELEMENT_PAGE_TITLE'] ?></h1>
                <?= $arResult['DETAIL_TEXT'] ?>
                <a class="ms-button ms-button-primary oborudovanie-open" href="#">Оставить заявку</a>
            </div>
            <div class="oborudovanie-head__image">
                <img src="<?= $arResult['DETAIL_PICTURE']['SRC'] ?>" alt="Автоматизация розницы под ключ" width="<?= $arResult['DETAIL_PICTURE']['WIDTH'] / 2 ?>" height="<?= $arResult['DETAIL_PICTURE']['HEIGHT'] / 2 ?>">
            </div>
        </div>
    </div>
</div>
<div class="oborudovanie-card">
    <div class="container">
        <div class="grid">
            <div class="col-xs-12 col-sm-4">
                <div class="oborudovanie-card__item">
                    <div class="oborudovanie-card__tetle">Необходимая техника</div>
                    <div class="oborudovanie-card__description">Проверенные модели ККТ для вашего бизнеса. Интеграция с ОФД</div>
                </div>
            </div>
            <div class="col-xs-12 col-sm-4">
                <div class="oborudovanie-card__item">
                    <div class="oborudovanie-card__tetle">Все по закону</div>
                    <div class="oborudovanie-card__description">Полное соответствие законам об онлайн-кассах и маркировке товаров</div>
                </div>
            </div>
            <div class="col-xs-12 col-sm-4">
                <div class="oborudovanie-card__item">
                    <div class="oborudovanie-card__tetle">Быстрый старт </div>
                    <div class="oborudovanie-card__description">Помощь в настройке, сопровождение партнерами и поддержка 24/7</div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="oborudovanie-tool">
    <div class="container">
        <div class="oborudovanie-tool__tetle">
            <h2>Комплекты торгового <br class="d-none d-lg-block"> оборудования</h2>
        </div>
        <div class="oborudovanie-tool__description">
            <p>— Выберите готовый комплект или <br class="d-none d-lg-block"> мы поможем собрать подходящий.</p>
            <p>— Все модели онлайн-касс соответствуют 54-ФЗ <br class="d-none d-lg-block"> и включены в госреестр контрольно-кассовой техники.</p>
            <p>— Подходят рознице, общепиту, сфере услуг.</p>
        </div>
        <? foreach ($arResult['OBORUDOVANIE'] as $key => $value) : ?>
            <div class="oborudovanie-tool__item">
                <div class="grid">
                    <div class="col-12 col-md-6 order-2 order-md-1">
                        <div class="oborudovanie-tool__item-tetle"><?= $value['UF_NAME'] ?></div>
                        <div class="oborudovanie-tool__item-description"><?= $value['UF_DESCRIPTION'] ?></div>
                        <ul>
                            <? for ($i = 1; $i < 5; $i++) : ?>
                                <? if (!empty($value['UF_NAIMENOVANIE_' . $i]) && !empty($value['UF_PRICE_' . $i])) : ?>
                                    <li><?= $value['UF_NAIMENOVANIE_' . $i] ?> <span><?= number_format($value['UF_PRICE_' . $i], 0, '', ' ') ?> ₽</span></li>
                                <? endif ?>
                            <? endfor ?>
                        </ul>
                        <div class="container">
                            <div class="grid">
                                <a class="ms-button ms-button-primary oborudovanie-open order-2 order-sm-1" href="#" data_oborudovanie="<?= $value['UF_NAME'] ?>">Заказать</a>
                                <div class="oborudovanie-tool__item-price order-1 order-sm-2">Цена: <?= number_format($value['ITOGO'], 0, '', ' ') ?>₽</div>
                            </div>
                        </div>
                    </div>
                    <div class="col-12 col-md-6 order-1 order-md-2">
                        <img src="<?= $value['PICTURE']['SRC'] ?>" alt=" <?= $value['UF_NAME'] ?>">
                    </div>
                </div>
            </div>
        <? endforeach ?>
    </div>
</div>
<div class="oborudovanie-icemaker">
    <div class="container">
        <div class="oborudovanie-icemaker__card with-3">
            <div class="oborudovanie-icemaker__card-item oborudovanie-icemaker__card-item--full">
                <h3>Возьмем все <br class="d-none d-sm-block"> вопросы на себя</h3>
                <p>Подбираем и настраиваем: <br> ККТ, сканеры штрихкодов, ТСД, принтеры для печати этикеток и другое оборудование.</p>
                <p>Также настраиваем интеграцию с товароучетной системой персонально под ваши задачи.</p>
                <svg viewBox="0 0 470 255" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <g clip-path="url(#clip0_99_7750)">
                        <rect x="83" y="1" width="170" height="170" rx="36.7188" fill="url(#paint0_radial_99_7750)" />
                        <g clip-path="url(#clip1_99_7750)">
                            <path d="M145.943 75.3536L161.727 50.1236C162.339 49.1264 163.198 48.3046 164.222 47.7383C165.246 47.172 166.399 46.8805 167.569 46.8922V46.8922C168.49 46.8589 169.409 47.0107 170.27 47.3385C171.132 47.6664 171.919 48.1636 172.585 48.8009C173.252 49.4381 173.783 50.2025 174.149 51.0487C174.515 51.895 174.707 52.806 174.715 53.7279V71.8115H201.996C203.004 71.8442 203.993 72.0899 204.9 72.5324C205.806 72.9749 206.608 73.6043 207.254 74.3791C207.9 75.1539 208.374 76.0566 208.646 77.0279C208.918 77.9991 208.981 79.0169 208.831 80.0143L203.86 112.08C203.648 113.794 202.817 115.371 201.524 116.515C200.231 117.66 198.565 118.292 196.838 118.294H156.072C154.132 118.302 152.216 117.855 150.479 116.989L146.005 114.752" stroke="white" stroke-width="9.17969" stroke-linecap="round" stroke-linejoin="round" />
                            <path d="M145.943 75.3542V114.566" stroke="white" stroke-width="9.17969" stroke-linecap="round" stroke-linejoin="round" />
                            <path d="M131.214 75.3535H145.942V114.566H131.214C130.39 114.566 129.6 114.238 129.017 113.656C128.435 113.073 128.107 112.283 128.107 111.459V78.4607C128.107 77.6366 128.435 76.8463 129.017 76.2636C129.6 75.6809 130.39 75.3535 131.214 75.3535V75.3535Z" stroke="white" stroke-width="9.17969" stroke-linecap="round" stroke-linejoin="round" />
                        </g>
                        <rect x="217" y="86" width="170" height="170" rx="36.7188" fill="white" />
                        <path d="M288.864 137.428L291.813 129.817C292.31 128.528 293.185 127.42 294.323 126.637C295.461 125.854 296.808 125.433 298.19 125.428H303.813C305.194 125.433 306.542 125.854 307.68 126.637C308.818 127.42 309.692 128.528 310.19 129.817L313.138 137.428L323.15 143.188L331.241 141.954C332.588 141.771 333.96 141.993 335.181 142.591C336.402 143.19 337.417 144.137 338.098 145.314L340.841 150.114C341.544 151.31 341.868 152.69 341.77 154.074C341.672 155.457 341.157 156.778 340.293 157.863L335.287 164.24V175.76L340.43 182.137C341.294 183.222 341.809 184.543 341.907 185.926C342.005 187.31 341.681 188.69 340.978 189.886L338.235 194.686C337.554 195.862 336.539 196.81 335.318 197.408C334.097 198.007 332.726 198.228 331.378 198.046L323.287 196.811L313.275 202.571L310.327 210.183C309.83 211.471 308.955 212.58 307.817 213.363C306.679 214.146 305.331 214.567 303.95 214.571H298.19C296.808 214.567 295.461 214.146 294.323 213.363C293.185 212.58 292.31 211.471 291.813 210.183L288.864 202.571L278.853 196.811L270.761 198.046C269.414 198.228 268.043 198.007 266.822 197.408C265.601 196.81 264.585 195.862 263.904 194.686L261.161 189.886C260.458 188.69 260.134 187.31 260.232 185.926C260.33 184.543 260.845 183.222 261.71 182.137L266.715 175.76V164.24L261.573 157.863C260.708 156.778 260.193 155.457 260.095 154.074C259.997 152.69 260.321 151.31 261.024 150.114L263.767 145.314C264.448 144.137 265.463 143.19 266.684 142.591C267.905 141.993 269.277 141.771 270.624 141.954L278.715 143.188L288.864 137.428ZM287.287 170C287.287 172.712 288.091 175.364 289.598 177.619C291.105 179.874 293.247 181.632 295.753 182.67C298.259 183.708 301.016 183.98 303.677 183.451C306.337 182.921 308.781 181.615 310.699 179.697C312.617 177.779 313.923 175.336 314.452 172.675C314.981 170.015 314.709 167.258 313.671 164.752C312.633 162.246 310.876 160.104 308.62 158.597C306.365 157.09 303.714 156.286 301.001 156.286C297.364 156.286 293.876 157.73 291.304 160.302C288.732 162.874 287.287 166.363 287.287 170Z" fill="url(#paint1_radial_99_7750)" />
                    </g>
                    <defs>
                        <radialGradient id="paint0_radial_99_7750" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(185.398 189.007) rotate(-111.896) scale(274.58 311.853)">
                            <stop stop-color="#1EB4FF" />
                            <stop offset="0.933093" stop-color="#64C8FF" stop-opacity="0" />
                            <stop offset="1" stop-color="#64C8FF" stop-opacity="0" />
                        </radialGradient>
                        <radialGradient id="paint1_radial_99_7750" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(309.377 224.013) rotate(-110.255) scale(142.401 151.808)">
                            <stop stop-color="#1EB4FF" />
                            <stop offset="0.933093" stop-color="#64C8FF" stop-opacity="0" />
                            <stop offset="1" stop-color="#64C8FF" stop-opacity="0" />
                        </radialGradient>
                        <clipPath id="clip0_99_7750">
                            <rect width="470" height="254" fill="white" transform="translate(0 0.750977)" />
                        </clipPath>
                        <clipPath id="clip1_99_7750">
                            <rect width="87" height="87" fill="white" transform="translate(125 39)" />
                        </clipPath>
                    </defs>
                </svg>
            </div>
            <div class="oborudovanie-icemaker__card-item oborudovanie-icemaker__card-item--one">
                <p>Наши партнеры подберут оборудование и предложат программное обеспечение</p>
            </div>
            <div class="oborudovanie-icemaker__card-item oborudovanie-icemaker__card-item--one">
                <p>Доставят, подключат и настроят всю необходимую технику</p>
            </div>
        </div>
    </div>
</div>
Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг