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

Создание комплексного компонента в d7

Комплексные компоненты необходимо использовать в случаях, когда функционал состоит из нескольких страниц с простыми компонентами:

  1. Более удобно использовать если планируется использовать ЧПУ, но только если все страницы с простыми компонентами имеют первую общую часть url. Например, страница со списком записей раздела имеет маску адреса /test/#SECTION_CODE#/, а страница детального описания имеет маску /test/#SECTION_CODE#/#ELEMENT_CODE#/, неизменяемая общая часть у них, это /test/
  2. Один раз при разработке комплексного компонента достаточно прописать параметры компонентов и при повторном использовании комплексного компонента, не нужно следить за связью настроек простых компонентов.

Основное отличие комплексного компонента от простого, заключается в структуре шаблона. У простого компонента в шаблоне стандартно подключается template.php, а шаблон комплексного компонента всегда имеет более одного файла и основная задача комплексного компонента, это определение какой конкретно файл шаблона подключить в зависимости от url страницы. Сам комплексный компонент не должен выполнять логику, за это должны отвечать простые компоненты, которые подключаются на конкретной странице шаблона.

Комплексный компонент может обрабатывать как минимум два режима, споддепжкой и без поддержки ЧПУ, определяется настройкой SEF_MODE. После включения ЧПУ SEF_MODE в режиме редактирования и сохранения настроек компонента через интерфейс битрикса, добавляется элемент массива с параметрами в массив файл urlrewrite.php, лучше всеравно проверять файл urlrewrite.php, для контроля правил.

Структура компонента

  • Папка my_components пространство имен
  • Папка hmarketing в ней расположен комплексный компонент
    • Папка /templates/.default/
      • Файл element.php отвечает за вывод элементов
      • Файл index.php отвечает за вывод стартовой страницы
      • Файл section.php отвечает за вывод секций
  • Папка hmarketing.element в ней расположен обычный компонент отвечающий за вывод элементов
    • Папка /templates/.default/
      • Файл template.php шаблон компонента
    • Файл .description.php содержит название, описание компонента и его положение в дереве логического размещения (для редактора). Этот файл должен всегда присутствовать в папке компонента. Его отсутствие не скажется на работе компонента, но размещение компонента через визуальный редактор станет невозможным
    • Файл .parameters.php который содержит описание входных параметров компонента для редактора. Если у компонента есть входные параметры, то этот файл должен присутствовать в папке компонента
    • Файл class.php содержит логику компонента
  • Папка hmarketing.index в которой расположен обычный компонент отвечающий за вывод первоначальной информации
    • Папка /templates/.default/
      • Файл template.php шаблон компонента
    • Файл .description.php содержит название, описание компонента и его положение в дереве логического размещения (для редактора). Этот файл должен всегда присутствовать в папке компонента. Его отсутствие не скажется на работе компонента, но размещение компонента через визуальный редактор станет невозможным
    • Файл .parameters.php который содержит описание входных параметров компонента для редактора. Если у компонента есть входные параметры, то этот файл должен присутствовать в папке компонента
    • Файл class.php содержит логику компонента
  • Папка hmarketing.section в которой расположен обычный компонент отвечающий за вывод секций
    • Папка /templates/.default/
      • Файл template.php шаблон компонента
    • Файл .description.php содержит название, описание компонента и его положение в дереве логического размещения (для редактора). Этот файл должен всегда присутствовать в папке компонента. Его отсутствие не скажется на работе компонента, но размещение компонента через визуальный редактор станет невозможным
    • Файл .parameters.php который содержит описание входных параметров компонента для редактора. Если у компонента есть входные параметры, то этот файл должен присутствовать в папке компонента
    • Файл class.php содержит логику компонента

Вместо файла template.php, в папке шаблона комплексного компонента находятся три файла, element.php, section.php, index.php. В зависимости от параметров или маски url, комплексный компонент будет подключать один из этих файлов с переменными, которые найдены по url-маске.

.parameters.php

Параметры компонента для ЧПУ.

my_components/hmarketing/.parameters.php<?
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
// пространства имен для загрузки необходимых файлов, классов, модулей
use Bitrix\Main\Loader;
// проверяем установку модуля «Информационные блоки»
if (!CModule::IncludeModule('iblock')) {
    return;
}
// подключаем модуль «Информационные блоки»
Loader::includeModule('iblock');
// получаем массив всех типов инфоблоков для возможности выбора
$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'];
}
// настройки компонента, формируем массив $arParams
$arComponentParameters = [
    // основной массив с параметрами
    "PARAMETERS" => [
        // выбор типа инфоблока
        'IBLOCK_TYPE' => array(                  // ключ массива $arParams в component.php
            'PARENT' => 'BASE',                  // название группы
            'NAME' => 'Выберите тип инфоблока',  // название параметра
            'TYPE' => 'LIST',                    // тип элемента управления, в котором будет устанавливаться параметр
            'VALUES' => $arIBlockType,           // входные значения
            'REFRESH' => 'Y',                    // перегружать настройки или нет после выбора (N/Y)
            'DEFAULT' => 'news',                 // значение по умолчанию
            'MULTIPLE' => 'N',                   // одиночное/множественное значение (N/Y)
        ),
        // выбор самого инфоблока
        'IBLOCK_ID' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Выберите родительский инфоблок',
            'TYPE' => 'LIST',
            'VALUES' => $arInfoBlocks,
            'REFRESH' => 'Y',
            "DEFAULT" => '',
            "ADDITIONAL_VALUES" => "Y",
        ),
        // настройки режима без ЧПУ, доступно в админке до активации чекбокса
        "VARIABLE_ALIASES" => [
            // элемент
            "ELEMENT_ID" => [
                "NAME" => 'GET параметр для ID элемента без ЧПУ',
                "DEFAULT" => "ELEMENT_ID",
            ],
            // секция
            "SECTION_ID" => [
                "NAME" => 'GET параметр для ID раздела без ЧПУ',
                "DEFAULT" => "SECTION_ID",
            ],
            // базовый URL
            "CATALOG_URL" => [
                "NAME" => 'Базовый URL каталога без ЧПУ',
                "DEFAULT" => "/test/",
            ]
        ],
        // настройки режима ЧПУ, доступно в админке после активации чекбокса
        "SEF_MODE" => [
            // настройки для секции
            "section" => [
                "NAME" => 'Страница раздела',
                "DEFAULT" => "#SECTION_CODE#/",
            ],
            // настройки для элемента
            "element" => [
                "NAME" => 'Детальная страница',
                "DEFAULT" => "#SECTION_CODE#/#ELEMENT_CODE#/",
            ]
        ],
    ]
];

class.php

Определяет какой шаблон подключить и отдача 404 если шаблон не найден.

my_components/hmarketing/class.php<?
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
// проверяем установку модуля «Информационные блоки»
if (!CModule::IncludeModule('iblock')) {
    return;
}
// пространство имен для 404 ошибки
use Bitrix\Iblock\Component\Tools;
// пространство имен для загрузки необходимых файлов, классов, модулей
use Bitrix\Main\Loader;
// пространство имен для обращения к глобальным сущностям ядра
use \Bitrix\Main\Application;
class ComplexComponent extends CBitrixComponent
{
    // выполняет основной код компонента, аналог конструктора (метод подключается автоматически)
    public function executeComponent()
    {
        // подключаем модуль «Информационные блоки»
        Loader::includeModule('iblock');
        // если выбран режим поддержки ЧПУ, вызываем метод sefMode()
        if ($this->arParams["SEF_MODE"] === "Y") {
            $componentPage = $this->sefMode();
        }
        // если отключен режим поддержки ЧПУ, вызываем метод noSefMode()
        if ($this->arParams["SEF_MODE"] != "Y") {
            $componentPage = $this->noSefMode();
        }
        // отдаем 404 статус если не найден шаблон
        if (!$componentPage) {
            Tools::process404(
                $this->arParams["MESSAGE_404"],
                ($this->arParams["SET_STATUS_404"] === "Y"),
                ($this->arParams["SET_STATUS_404"] === "Y"),
                ($this->arParams["SHOW_404"] === "Y"),
                $this->arParams["FILE_404"]
            );
        }
        // подключается файл php из папки комплексного компонента по имени файла, если $componentPage=section, значит подключится section.php расположенный по пути templates/.default
        $this->IncludeComponentTemplate($componentPage);
    }
    // метод обработки режима ЧПУ
    protected function sefMode()
    {
        //******************************************************//
        // Обработка GET параметров                             //
        //******************************************************//
        // дополнительные GET параметры которые будем отлавливать в запросе, в массив $arVariables будет добавлена переменная sort, значение которой будет получено из $_REQUEST['sort'], применяется когда не нужно указывать точный псевдоним для ключа 
        $arComponentVariables = [
            'sort'
        ];
        // дополнительные GET параметры которые будем отлавливать в запросе, полезно например для постраничной навигации. В массив $arVariableAliases будет добавлена переменная ELEMENT_COUNT, значение которой будет получено из $_REQUEST['count'], отлавливаться параметр будет только в разделе section, в итоге данные попадут в $arVariables, применяется когда нужно указать точный псевдоним для ключа 
        $arDefaultVariableAliases404 = array(
            'section' => array(
                'ELEMENT_COUNT' => 'count',
            )
        );
        // метод предназначен для объединения дефолтных GET параметров которые приходят в $arParams["VARIABLE_ALIASES"], в режиме ЧПУ $arParams["VARIABLE_ALIASES"] будет пустой и дополнительных GET параметров из массива $arDefaultVariableAliases404. Параметры из настроек $arrParams заменяют дополнительные из $arDefaultVariableAliases404
        $arVariableAliases = CComponentEngine::makeComponentVariableAliases(
            // массив псевдонимов переменных из GET параметра
            $arDefaultVariableAliases404,
            // массив псевдонимов из $arParams, в режиме ЧПУ $arParams["VARIABLE_ALIASES"] будет пустой
            $this->arParams["VARIABLE_ALIASES"]
        );
        //*****************************************************//
        // Обработка данных по маске из URL запроса           //
        //*****************************************************//
        // если в комплексном компоненте не задан базовый URL
        if (empty($this->arParams["SEF_FOLDER"])) {
            // получаем данные из настроек инфоблока
            $dbResult = CIBlock::GetByID($this->arParams["IBLOCK_ID"])->GetNext();
            if (!empty($dbResult)) {
                // перетираем данные в $arParams["SEF_URL_TEMPLATES"]
                $this->arParams["SEF_URL_TEMPLATES"]["element"] = $dbResult["DETAIL_PAGE_URL"];
                $this->arParams["SEF_URL_TEMPLATES"]["section"] = $dbResult["SECTION_PAGE_URL"];
                $this->arParams["SEF_FOLDER"] = $dbResult["LIST_PAGE_URL"];
            }
        }
        // значение маски URL по умолчанию
        $arDefaultUrlTemplates404 = [
            "section" => "#SECTION_CODE#/",
            "element" => "#SECTION_CODE#/#ELEMENT_CODE#/",
        ];
        // метод предназначен для объединения дефолтных параметров масок URL которые приходят в arParams["SEF_URL_TEMPLATES"] и из массива $arDefaultUrlTemplates404. Параметры из настроек $arrParams заменяют дефолтные из $arDefaultUrlTemplates404
        $arUrlTemplates = CComponentEngine::makeComponentUrlTemplates(
            // массив переменных с масками по умолчанию
            $arDefaultUrlTemplates404,
            // массив переменных с масками из входных параметров $arParams["SEF_URL_TEMPLATES"]
            $this->arParams["SEF_URL_TEMPLATES"]
        );
        //*****************************************************//
        // Получение шаблона для подключения                   //
        //*****************************************************//
        // объект для поиска шаблонов
        $engine = new CComponentEngine($this);
        // главная переменная комплексного компонента, именно она будут записана в массив $arResult, как результат работы комплексного компонента. Она будет доступна в файлах section.php, element.php, index.php, которые будут подключены, после того как отработает class.php
        $arVariables = [];
        // определение шаблона, какой файл подключать section.php, element.php, index.php и заполнение $arVariables получеными URL в соответствие с масками
        $componentPage = $engine->guessComponentPath(
            // путь до корня секции
            $this->arParams["SEF_FOLDER"],
            // массив масок
            $arUrlTemplates,
            // путь до секции SECTION_CODE и элемента ELEMENT_CODE
            $arVariables
        );
        // проверяем, если не удалось сопоставить шаблон, значит выводим index.php
        if ($componentPage == FALSE) {
            $componentPage = 'index';
        }
        //*****************************************************//
        // Формируем $arResult                                 //
        //*****************************************************//
        // метод предназначен для объединения GET и URL параметров, результат записываем в $arVariables
        CComponentEngine::initComponentVariables(
            // нужен для режима ЧПУ, содержит файл который будет подключен section.php, element.php, index.php
            $componentPage,
            // массив дополнительных GET параметров без псевдонимов
            $arComponentVariables,
            // массив основных GET параметров с псевдонимами
            $arVariableAliases,
            // обьединяем все найденные URL и GET параметры и записываем в переменну
            $arVariables
        );
        // формируем arResult
        $this->arResult = [
            // данные полученые из GET и URL параметров 
            "VARIABLES" => $arVariables,
            // массив с параметрами псевдонимов для возможности востановления дальше в обычном компоненте
            "ALIASES" => $arVariableAliases
        ];
        return $componentPage;
    }
    // метод обработки режима без ЧПУ
    protected function noSefMode()
    {
        //******************************************************//
        // Переименование GET параметров                        //
        //******************************************************//
        // если в комплексном компоненте не задан базовый URL
        if (empty($this->arParams["VARIABLE_ALIASES"]["CATALOG_URL"])) {
            // получаем данные из настроек инфоблока
            $dbResult = CIBlock::GetByID($this->arParams["IBLOCK_ID"])->GetNext();
            if (!empty($dbResult)) {
                // перетираем данные в $arParams["VARIABLE_ALIASES"]
                $this->arParams["VARIABLE_ALIASES"]["ELEMENT_ID"] = preg_replace('/\#/', '', $dbResult["DETAIL_PAGE_URL"]);
                $this->arParams["VARIABLE_ALIASES"]["SECTION_ID"] = preg_replace('/\#/', '', $dbResult["SECTION_PAGE_URL"]);
                $this->arParams["VARIABLE_ALIASES"]["CATALOG_URL"] = preg_replace('/\#/', '', $dbResult["LIST_PAGE_URL"]);
            }
        }
        // дополнительные GET параметры которые будем отлавливать в запросе, полезно например для постраничной навигации. В массив $arVariableAliases будет добавлена переменная ELEMENT_COUNT, значение которой будет получено из $_REQUEST['count'], в итоге данные попадут в $arVariables, применяется когда нужно указать точный псевдоним для ключа 
        $arDefaultVariableAliases = [
            'ELEMENT_COUNT' => 'count',
        ];
        // метод предназначен для объединения дефолтных GET параметров которые приходят в $arParams["VARIABLE_ALIASES"] и дополнительных GET параметров из массива $arDefaultVariableAliases. Параметры из настроек $arrParams заменяют дополнительные из $arDefaultVariableAliases
        $arVariableAliases = CComponentEngine::makeComponentVariableAliases(
            // массив псевдонимов переменных из GET параметра
            $arDefaultVariableAliases,
            // массив псевдонимов из $arParams
            $this->arParams["VARIABLE_ALIASES"]
        );
        //******************************************************//
        // Получение и обьединение GET параметров               //
        //******************************************************//
        // главная переменная комплексного компонента, именно она будут записана в массив $arResult, как результат работы комплексного компонента. Она будет доступна в файлах section.php, element.php, index.php, которые будут подключены, после того как отработает class.php
        $arVariables = [];
        // дополнительные GET параметры которые будем отлавливать в запросе, в массив $arVariables будет добавлена переменная sort, значение которой будет получено из $_REQUEST['sort'], применяется когда не нужно указывать точный псевдоним для ключа 
        $arComponentVariables = [
            'sort'
        ];
        // метод предназначен для получения и объединения GET параметров результат записываем в $arVariables
        CComponentEngine::initComponentVariables(
            // нужен для режима ЧПУ, содержит файл который будет подключен section.php, element.php, index.php
            false,
            // массив дополнительных GET параметров без псевдонимов
            $arComponentVariables,
            // массив основных GET параметров с псевдонимами
            $arVariableAliases,
            // обьединяем все найденные GET параметры и записываем в переменну
            $arVariables
        );
        //*****************************************************//
        // Получение реального URL                             //
        //*****************************************************//
        // получаем контекст текущего хита
        $context = Application::getInstance()->getContext();
        // получаем объект Request
        $request = $context->getRequest();
        // получаем директорию запрошенной страницы
        $rDir = $request->getRequestedPageDirectory();
        //*****************************************************//
        // Получение нужного шаблона                           //
        //*****************************************************//
        // переменная предназначен для хранения подключаемого шаблона section.php, element.php, index.php
        $componentPage = "";
        // если запрошенная директория равна переданой в arParams["CATALOG_URL"], определяем тип страницы стартовая 
        if ($arVariableAliases["CATALOG_URL"] == $rDir) {
            $componentPage = "index";
        }
        // по найденным параметрам $arVariables определяем тип страницы секция
        if ((isset($arVariables["SECTION_ID"]) && intval($arVariables["SECTION_ID"]) > 0) || (isset($arVariables["SECTION_CODE"]) && $arVariables["SECTION_CODE"] <> '')) {
            $componentPage = "section";
        }
        // по найденным параметрам $arVariables определяем тип страницы элемент
        if ((isset($arVariables["ELEMENT_ID"]) && intval($arVariables["ELEMENT_ID"]) > 0) || (isset($arVariables["ELEMENT_CODE"]) && $arVariables["ELEMENT_CODE"] <> '')) {
            $componentPage = "element";
        }
        //*****************************************************//
        // Формируем $arResult                                 //
        //*****************************************************//
        // формируем $arResult
        $this->arResult = [
            // данные полученые из GET параметров 
            "VARIABLES" => $arVariables,
            // массив с параметрами псевдонимов для возможности востановления дальше в обычном компоненте
            "ALIASES" => $arVariableAliases
        ];
        return $componentPage;
    }
}

Подключение компонента на странице

Маски URL по которым работает комплексный компонент, могут браться из трех мест:

  1. Из настроек инфоблока
  2. Из настрое при вызове компонента $arParams
  3. Логика может быть прописана в самом компоненте

В настройках инфоблока:

В настройках при подключение:

В нашем случае подключать будем в разделе /test/ на странице index.php.

/test/index.php<?
$APPLICATION->IncludeComponent(
	"my_components:hmarketing",
	"",
	Array(
		"IBLOCK_ID" => "2",
		"IBLOCK_TYPE" => "products",
		"SEF_FOLDER" => "/test/",
		"SEF_MODE" => "Y",
		"SEF_URL_TEMPLATES" => Array("element"=>"#SECTION_CODE#/#ELEMENT_CODE#/","section"=>"#SECTION_CODE#/")
	)
);

Не забываем, если подключаем в режиме работы с поддержкой ЧПУ, то нужно в urlrewrite.php прописать правило:

urlrewrite.phparray (
    'CONDITION' => '#^/test/#',
    'RULE' => '',
    'ID' => 'my_components:hmarketing',
    'PATH' => '/test/index.php',
    'SORT' => 100,
)

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

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг