Битрикс. Создание комплексного компонента. Часть 3 из 4

21.09.2018

Теги: CMSresult_modifier.phpWeb-разработкаБитриксИнфоблокКомпонентРазделИнфоблокаШаблонКомпонентаЭлементИнфоблока

Все три простых компонента готовы, можно приступать к созданию комплексного компонента. Этот компонент будет уметь решать все три задачи, которые простые компоненты решали поодиночке: выводить главную страницу (корневые разделы + популярные элементы), раздел инфоблока (подразделы + список элементов) и детальную страницу элемента.

Комплексный компонент tokmakov:iblock

[local]
    [components]
        [tokmakov]
            [iblock]
            [iblock.element]
            [iblock.section]
            [iblock.popular]
[iblock]
    [templates]
        [.default]
            [tokmakov]
                [iblock.element]
                    [.default]
                        template.php
                        style.css
                [iblock.section]
                    [.default]
                        template.php
                        style.css
                [iblock.popular]
                    [.default]
                        template.php
                        style.css
            element.php
            section.php
            popular.php
    .description.php
    .parameters.php
    component.php
<?php
/*
 * Файл local/components/tokmakov/iblock/.description.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

$arComponentDescription = array(
    'NAME' => 'Инфоблок (комплексный)', // название компонента
    'DESCRIPTION' => 'Универсальный компонент для информационного блока',
    'ICON' => '/images/icon.gif', // иконка компонента относительно папки компонента
    'CACHE_PATH' => 'Y', // показывать кнопку очистки кеша
    'SORT' => 40, // порядок сортировки в визуальном редакторе
    'COMPLEX' => 'Y', // признак комплексного компонента
    'PATH' => array( // расположение компонента в визуальном редакторе
        'ID' => 'other_components', // идентификатор верхнего уровеня в редакторе
        'NAME' => 'Прочие компоненты', // название верхнего уровня в редакторе
        'CHILD' => array( // второй уровень в визуальном редакторе
            'ID' => 'other_iblock', // идентификатор второго уровня в редакторе
            'NAME' => 'Информационный блок' // название второго уровня в редакторе
        )
    )
);
<?php
/*
 * Файл local/components/tokmakov/iblock/.parameters.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

// проверяем, установлен ли модуль «Информационные блоки»; если да — то подключаем его
if (!CModule::IncludeModule('iblock')) {
    return;
}

/*
 * Получаем массив всех типов инфоблоков — для возможности выбора
 */
$arInfoBlockTypes = CIBlockParameters::GetIBlockTypes();

/*
 * Получаем массив инфоблоков — для возможности выбора; фильтруем их по
 * выбранному типу и по активности
 */
$arInfoBlocks = array();
$arFilter = array('ACTIVE' => 'Y');
// если уже выбран тип инфоблока, выбираем инфоблоки только этого типа
if (!empty($arCurrentValues['IBLOCK_TYPE'])) {
    $arFilter['TYPE'] = $arCurrentValues['IBLOCK_TYPE'];
}
$rsIBlock = CIBlock::GetList(
    array('SORT' => 'ASC'),
    $arFilter
);
while($iblock = $rsIBlock->Fetch()) {
    $arInfoBlocks[$iblock['ID']] = '['.$iblock['ID'].'] '.$iblock['NAME'];
}

/*
 * Получаем массив разделов инфоблока, из которых надо получать
 * популярные элементы — для возможности выбора
 */
$arInfoBlockSections = array(
    '-' => '[=Выберите=]',
);
$arFilter = array(
    'SECTION_ID' => false, // только корневые разделы
    'ACTIVE' => 'Y' // только активные разделы
);
// если уже выбран тип инфоблока, выбираем разделы, принадлежащие инфоблокам выбранного типа
if (!empty($arCurrentValues['IBLOCK_TYPE'])) {
    $arFilter['IBLOCK_TYPE'] = $arCurrentValues['IBLOCK_TYPE'];
}
// если уже выбран инфоблок, выбираем разделы только этого инфоблока
if (!empty($arCurrentValues['IBLOCK_ID'])) {
    $arFilter['IBLOCK_ID'] = $arCurrentValues['IBLOCK_ID'];
}
$result = CIBlockSection::GetList(
    array('SORT' => 'ASC'),
    $arFilter
);
while ($section = $result->Fetch()) {
    $arInfoBlockSections[$section['ID']] = '['.$section['ID'].'] '.$section['NAME'];
}

/*
 * Настройки комлексного компонента
 */
$arComponentParameters = array( // кроме групп по умолчанию, добавляем свои группы настроек
    'GROUPS' => array(
        'POPULAR_SETTINGS' => array(
            'NAME' => 'Настройки главной страницы',
            'SORT' => 800
        ),
        'SECTION_SETTINGS' => array(
            'NAME' => 'Настройки страницы раздела',
            'SORT' => 900
        ),
        'ELEMENT_SETTINGS' => array(
            'NAME' => 'Настройки страницы элемента',
            'SORT' => 1000
        ),
    ),
    /*
     * Группы параметров компонента:
     * 1. Основные параметры компонента (BASE)
     * 2. Параметры главной страницы (POPULAR_SETTINGS)
     * 3. Параметры страницы раздела (SECTION_SETTINGS)
     * 4. Параметры страницы элемента (DETAIL_SETTINGS)
     */
    'PARAMETERS' => array(

        /*
         * 1. Основные параметры компонента
         */
        'IBLOCK_TYPE' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Тип инфоблока',
            'TYPE' => 'LIST',
            'VALUES' => $arInfoBlockTypes,
            'REFRESH' => 'Y',
        ),
        'IBLOCK_ID' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Инфоблок',
            'TYPE' => 'LIST',
            'VALUES' => $arInfoBlocks,
            'REFRESH' => 'Y',
        ),
        // использовать символьный код вместо ID; если отмечен этот checkbox, в
        // визуальном редакторе надо будет обязательно изменить шаблоны ссылок
        // при включенном режиме поддержки ЧПУ, чтобы вместо #SECTION_ID# и
        // #ELEMENT_ID# использовались #SECTION_CODE# и #ELEMENT_CODE#
        'USE_CODE_INSTEAD_ID' => array(
            'PARENT' => 'BASE',
            'NAME' => 'Использовать символьный код вместо ID',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'N',
        ),
        // включать раздел в цепочку навигации?
        'ADD_SECTIONS_CHAIN' => Array(
            'PARENT' => 'BASE',
            'NAME' => 'Включать родителей в цепочку навигации',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),

        /*
         * 2. Параметры главной страницы
         */
        // показывать корневые разделы инфоблока?
        'POPULAR_ROOT_SECTIONS' => array(
            'PARENT' => 'POPULAR_SETTINGS',
            'NAME' => 'Показывать корневые разделы',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        // выбор разделов инфоблока, откуда будем получать популярные элементы
        'POPULAR_SECTIONS' => array(
            'PARENT' => 'POPULAR_SETTINGS',
            'NAME' => 'Выберите разделы инфоблока',
            'TYPE' => 'LIST',
            'VALUES' => $arInfoBlockSections,
            'MULTIPLE'=>'Y',
            'REFRESH' => 'Y',
        ),
        // максимальное количество популярных элементов в разделе
        'POPULAR_ELEMENT_COUNT' => array(
            'PARENT' => 'POPULAR_SETTINGS',
            'NAME' => 'Максимальное количество элементов в разделе',
            'TYPE' => 'STRING',
            'DEFAULT' => '3',
        ),
        'POPULAR_SET_PAGE_TITLE' => array(
            'PARENT' => 'POPULAR_SETTINGS',
            'NAME' => 'Устанавливать заголовок страницы из названия инфоблока',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'POPULAR_SET_BROWSER_TITLE' => array(
            'PARENT' => 'POPULAR_SETTINGS',
            'NAME' => 'Устанавливать заголовок окна браузера из названия инфоблока',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),

        /*
         * 3. Параметры страницы раздела
         */
        'SECTION_ELEMENT_COUNT' => array(
            'PARENT' => 'SECTION_SETTINGS',
            'NAME' => 'Количество элементов на странице',
            'TYPE' => 'STRING',
            'DEFAULT' => '3',
        ),
        'SECTION_SET_PAGE_TITLE' => array(
            'PARENT' => 'SECTION_SETTINGS',
            'NAME' => 'Устанавливать заголовок страницы для раздела',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'SECTION_SET_BROWSER_TITLE' => array(
            'PARENT' => 'SECTION_SETTINGS',
            'NAME' => 'Устанавливать заголовок окна браузера для раздела',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'SECTION_SET_META_KEYWORDS' => array(
            'PARENT' => 'SECTION_SETTINGS',
            'NAME' => 'Устанавливать мета-тег keywords для раздела',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'SECTION_SET_META_DESCRIPTION' => array(
            'PARENT' => 'SECTION_SETTINGS',
            'NAME' => 'Устанавливать мета-тег description для раздела',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),

        /*
         * 4. Параметры страницы элемента
         */
        'ELEMENT_SET_PAGE_TITLE' => array(
            'PARENT' => 'ELEMENT_SETTINGS',
            'NAME' => 'Устанавливать заголовок страницы для элемента',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'ELEMENT_SET_BROWSER_TITLE' => array(
            'PARENT' => 'ELEMENT_SETTINGS',
            'NAME' => 'Устанавливать заголовок окна браузера для элемента',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'ELEMENT_SET_META_KEYWORDS' => array(
            'PARENT' => 'ELEMENT_SETTINGS',
            'NAME' => 'Устанавливать мета-тег keywords для элемента',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
        'ELEMENT_SET_META_DESCRIPTION' => array(
            'PARENT' => 'ELEMENT_SETTINGS',
            'NAME' => 'Устанавливать мета-тег description для элемента',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),

        /*
         * Это отдельный блок настроек, который задает работу
         * в обычном режиме (без ЧПУ) и в режиме ЧПУ
         */
        'VARIABLE_ALIASES' => array( // это для работы в режиме без ЧПУ
            'SECTION_ID' => array('NAME' => 'Идентификатор раздела'),
            'SECTION_CODE' => array('NAME' => 'Символьный код раздела'),
            'ELEMENT_ID' => array('NAME' => 'Идентификатор элемента'),
            'ELEMENT_CODE' => array('NAME' => 'Символьный код элемента'),
        ),
        'SEF_MODE' => array( // это для работы в режиме ЧПУ
            'popular' => array(
                'NAME' => 'Главная страница',
                'DEFAULT' => '',
            ),
            'section' => array(
                'NAME' => 'Страница раздела',
                'DEFAULT' => 'category/id/#SECTION_ID#/',
            ),
            'element' => array(
                'NAME' => 'Страница элемента',
                'DEFAULT' => 'item/id/#ELEMENT_ID#/',
            ),
        ),

        /*
         * Настройки кэширования
         */
        'CACHE_TIME'  =>  array('DEFAULT' => 3600),
        'CACHE_GROUPS' => array( // учитываться права доступа при кешировании?
            'PARENT' => 'CACHE_SETTINGS',
            'NAME' => 'Учитывать права доступа',
            'TYPE' => 'CHECKBOX',
            'DEFAULT' => 'Y',
        ),
    ),
);

// настройка постраничной навигации
CIBlockParameters::AddPagerSettings(
    $arComponentParameters,
    'Элементы',  // $pager_title
    false,       // $bDescNumbering
    true         // $bShowAllParam
);

// настройки на случай, если раздел или элемент не найдены, 404 Not Found
CIBlockParameters::Add404Settings($arComponentParameters, $arCurrentValues);
<?php
/*
 * Файл local/components/tokmakov/iblock/component.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

/** @var CBitrixComponent $this */
/** @var array $arParams */
/** @var array $arResult */
/** @var string $componentPath */
/** @var string $componentName */
/** @var string $componentTemplate */
/** @global CDatabase $DB */
/** @global CUser $USER */
/** @global CMain $APPLICATION */

if ($arParams['SEF_MODE'] == 'Y') {
    /*
     * Если включен режим поддержки ЧПУ
     */

    // В этой переменной будем накапливать значения истинных переменных
    $arVariables = array();


     // Определим имя файла (popular, section, element), которому соответствует текущая запрошенная
     // страница. Кроме того, восстанавим те переменные, которые были заданы с помощью шаблона.
    $componentPage = CComponentEngine::ParseComponentPath(
        $arParams['SEF_FOLDER'],
        $arParams['SEF_URL_TEMPLATES'], 
        $arVariables // переменная передается по ссылке
    );

    // Метод выше не обрабатывает случай, когда шаблон пути равен пустой строке,
    // (например 'popular' => ''), поэтому делаем это сами
    if ($componentPage === false && parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == $arParams['SEF_FOLDER']) {
        $componentPage = 'popular';
    }

    // Если определить файл шаблона не удалось, показываем  страницу 404 Not Found
    if (empty($componentPage)) {
        \Bitrix\Iblock\Component\Tools::process404(
            trim($arParams['MESSAGE_404']) ?: 'Элемент или раздел инфоблока не найден',
            true,
            $arParams['SET_STATUS_404'] === 'Y',
            $arParams['SHOW_404'] === 'Y',
            $arParams['FILE_404']
        );
        return;
    }

    /*
     * Обрабытываем ситуацию, когда переданы некорректные параметры SECTION_ID, SECTION_CODE, ELEMENT_ID,
     * ELEMENT_CODE и показываем страницу 404 Not Found
     */
    $notFound = false;
    // недопустимое значение идентификатора элемента
    if ($componentPage == 'element') {
        if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // если используются символьные коды
            if ( ! (isset($arVariables['ELEMENT_CODE']) && strlen($arVariables['ELEMENT_CODE']) > 0)) {
                $notFound = true;
            }
        } else { // если используются идентификаторы
            if ( ! (isset($arVariables['ELEMENT_ID']) && ctype_digit($arVariables['ELEMENT_ID']))) {
                $notFound = true;
            }
        }
    }
    // недопустимое значение идентификатора раздела
    if ($componentPage == 'section') {
        if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // если используются символьные коды
            if ( ! (isset($arVariables['SECTION_CODE']) && strlen($arVariables['SECTION_CODE']) > 0)) {
                $notFound = true;
            }
        } else { // если используются идентификаторы
            if ( ! (isset($arVariables['SECTION_ID']) && ctype_digit($arVariables['SECTION_ID']))) {
                $notFound = true;
            }
        }
    }
    // показываем страницу 404 Not Found
    if ($notFound) {
        \Bitrix\Iblock\Component\Tools::process404(
            trim($arParams['MESSAGE_404']) ?: 'Элемент или раздел инфоблока не найден',
            true,
            $arParams['SET_STATUS_404'] === 'Y',
            $arParams['SHOW_404'] === 'Y',
            $arParams['FILE_404']
        );
        return;
    }

    /*
     * Метод служит для поддержки псевдонимов переменных в комплексных компонентах. Восстанавливает
     * истинные переменные из $_REQUEST на основании их псевдонимов из $arParams['VARIABLE_ALIASES'].
     */
    CComponentEngine::InitComponentVariables(
        $componentPage,
        null,
        array(),
        $arVariables
    );

    $arResult['VARIABLES'] = $arVariables;
    $arResult['FOLDER'] = $arParams['SEF_FOLDER'];
    $arResult['SECTION_URL'] = $arParams['SEF_FOLDER'].$arParams['SEF_URL_TEMPLATES']['section'];
    $arResult['ELEMENT_URL'] = $arParams['SEF_FOLDER'].$arParams['SEF_URL_TEMPLATES']['element'];

} else {
    /*
     * Если не включен режим поддержки ЧПУ
     */

    // В этой переменной будем накапливать значения истинных переменных
    $arVariables = array();

    // Восстановим переменные, которые пришли в параметрах запроса и запишем их в $arVariables
    CComponentEngine::InitComponentVariables(
        false,
        null,
        $arParams['VARIABLE_ALIASES'],
        $arVariables
    );

    /*
     * Теперь на основании истинных переменных $arVariables можно определить, какую страницу
     * шаблона компонента нужно показать
     */
    $componentPage = '';
    if (isset($arVariables['ELEMENT_ID']) && intval($arVariables['ELEMENT_ID']) > 0)
        $componentPage = 'element'; // элемент инфоблока по идентификатору
    elseif (isset($arVariables['ELEMENT_CODE']) && strlen($arVariables['ELEMENT_CODE']) > 0)
        $componentPage = 'element'; // элемент инфоблока по символьному коду
    elseif (isset($arVariables['SECTION_ID']) && intval($arVariables['SECTION_ID']) > 0)
        $componentPage = 'section'; // раздел инфоблока по идентификатору
    elseif (isset($arVariables['SECTION_CODE']) && strlen($arVariables['SECTION_CODE']) > 0)
        $componentPage = 'section'; // раздел инфоблока по символьному коду
    else
        $componentPage = 'popular'; // главная страница компонента

    /*
     * Обрабытываем ситуацию, когда переданы некорректные параметры и показываем 404 Not Found
     */
    $notFound = false;
    // недопустимое значение идентификатора элемента
    if ($componentPage == 'element') {
        if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // если используются символьные коды
            if (!(isset($arVariables['ELEMENT_CODE']) && strlen($arVariables['ELEMENT_CODE']) > 0)) {
                $notFound = true;
            }
        } else { // если используются идентификаторы
            if (!(isset($arVariables['ELEMENT_ID']) && ctype_digit($arVariables['ELEMENT_ID']))) {
                $notFound = true;
            }
        }
    }
    // недопустимое значение идентификатора раздела
    if ($componentPage == 'section') {
        if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // если используются символьные коды
            if (!(isset($arVariables['SECTION_CODE']) && strlen($arVariables['SECTION_CODE']) > 0)) {
                $notFound = true;
            }
        } else { // если используются идентификаторы
            if (!(isset($arVariables['SECTION_ID']) && ctype_digit($arVariables['SECTION_ID']))) {
                $notFound = true;
            }
        }
    }
    // показываем страницу 404 Not Found
    if ($notFound) {
        \Bitrix\Iblock\Component\Tools::process404(
            trim($arParams['MESSAGE_404']) ?: 'Элемент или раздел инфоблока не найден',
            true,
            $arParams['SET_STATUS_404'] === 'Y',
            $arParams['SHOW_404'] === 'Y',
            $arParams['FILE_404']
        );
        return;
    }

    $arResult['VARIABLES'] = $arVariables;
    $arResult['FOLDER'] = '';
    if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // если используются символьные коды
        $arResult['SECTION_URL'] =
            $APPLICATION->GetCurPage().'?'.$arParams['VARIABLE_ALIASES']['SECTION_CODE'].'=#SECTION_CODE#';
        $arResult['ELEMENT_URL'] =
            $APPLICATION->GetCurPage().'?'.$arParams['VARIABLE_ALIASES']['ELEMENT_CODE'].'=#ELEMENT_CODE#';
    } else { // если используются идентификаторы
        $arResult['SECTION_URL'] =
            $APPLICATION->GetCurPage().'?'.$arParams['VARIABLE_ALIASES']['SECTION_ID'].'=#SECTION_ID#';
        $arResult['ELEMENT_URL'] =
            $APPLICATION->GetCurPage().'?'.$arParams['VARIABLE_ALIASES']['ELEMENT_ID'].'=#ELEMENT_ID#';
    }

}

$this->IncludeComponentTemplate($componentPage);
<?php
/*
 * Файл local/components/tokmakov/iblock/templates/.default/element.php
 */
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

/** @var array $arParams */
/** @var array $arResult */
/** @global CMain $APPLICATION */
/** @global CUser $USER */
/** @global CDatabase $DB */
/** @var CBitrixComponentTemplate $this */
/** @var string $templateName */
/** @var string $templateFile */
/** @var string $templateFolder */
/** @var string $componentPath */
/** @var CBitrixComponent $component */

$this->setFrameMode(true);
?>

<?php
$APPLICATION->IncludeComponent(
    'tokmakov:iblock.element',
    '',
    Array(
        'IBLOCK_TYPE' => $arParams['IBLOCK_TYPE'],                // тип инфоблока
        'IBLOCK_ID' => $arParams['IBLOCK_ID'],                    // идентификатор инфоблока

        //  использовать символьные коды вместо идентификаторов?
        'USE_CODE_INSTEAD_ID' => $arParams['USE_CODE_INSTEAD_ID'],
        // включать раздел в цепочку навигации?
        'ADD_SECTIONS_CHAIN' => $arParams['ADD_SECTIONS_CHAIN'],

        'ELEMENT_ID' => $arResult['VARIABLES']['ELEMENT_ID'],     // идентификатор элемента инфоблока
        'ELEMENT_CODE' => $arResult['VARIABLES']['ELEMENT_CODE'], // символьный код элемента инфоблока

        // настройки SEO
        'SET_PAGE_TITLE' => $arParams['ELEMENT_SET_PAGE_TITLE'],
        'SET_BROWSER_TITLE' => $arParams['ELEMENT_SET_BROWSER_TITLE'],
        'SET_META_KEYWORDS' => $arParams['ELEMENT_SET_META_KEYWORDS'],
        'SET_META_DESCRIPTION' => $arParams['ELEMENT_SET_META_DESCRIPTION'],

        // URL, ведущий на страницу с содержимым раздела
        'SECTION_URL' => $arResult['SECTION_URL'],
        // URL, ведущий на страницу с содержимым элемента
        'ELEMENT_URL' => $arResult['ELEMENT_URL'],

        // настройки кэширования
        'CACHE_TYPE' => $arParams['CACHE_TYPE'],
        'CACHE_TIME' => $arParams['CACHE_TIME'],
        'CACHE_GROUPS' => $arParams['CACHE_GROUPS'],
        
        // настройки страницы 404 Not Found
        'MESSAGE_404' => $arParams['MESSAGE_404'],
        'SET_STATUS_404' => $arParams['SET_STATUS_404'],
        'SHOW_404' => $arParams['SHOW_404'],
        'FILE_404' => $arParams['FILE_404'],
    ),
    $component
);
?>
<?php
/*
 * Файл local/components/tokmakov/iblock/templates/.default/section.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

/** @var array $arParams */
/** @var array $arResult */
/** @global CMain $APPLICATION */
/** @global CUser $USER */
/** @global CDatabase $DB */
/** @var CBitrixComponentTemplate $this */
/** @var string $templateName */
/** @var string $templateFile */
/** @var string $templateFolder */
/** @var string $componentPath */
/** @var CBitrixComponent $component */

$this->setFrameMode(true);
?>

<?php
$APPLICATION->IncludeComponent(
    'tokmakov:iblock.section',
    '',
    Array(
        'IBLOCK_TYPE' => $arParams['IBLOCK_TYPE'],                 // тип инфоблока
        'IBLOCK_ID' => $arParams['IBLOCK_ID'],                     // идентификатор инфоблока

        //  использовать символьные коды вместо идентификаторов?
        'USE_CODE_INSTEAD_ID' => $arParams['USE_CODE_INSTEAD_ID'],
        // включать раздел в цепочку навигации?
        'ADD_SECTIONS_CHAIN' => $arParams['ADD_SECTIONS_CHAIN'],

        'SECTION_ID' => $arResult['VARIABLES']['SECTION_ID'],      // идентификатор раздела инфоблока
        'SECTION_CODE' => $arResult['VARIABLES']['SECTION_CODE'],  // символьный код раздела инфоблока

        // количество элементов на странице
        'ELEMENT_COUNT' => $arParams['SECTION_ELEMENT_COUNT'],

        // настройки SEO
        'SET_PAGE_TITLE' => $arParams['SECTION_SET_PAGE_TITLE'],
        'SET_BROWSER_TITLE' => $arParams['SECTION_SET_BROWSER_TITLE'],
        'SET_META_KEYWORDS' => $arParams['SECTION_SET_META_KEYWORDS'],
        'SET_META_DESCRIPTION' => $arParams['SECTION_SET_META_DESCRIPTION'],

        // URL, ведущий на страницу с содержимым раздела
        'SECTION_URL' => $arResult['SECTION_URL'],
        // URL, ведущий на страницу с содержимым элемента
        'ELEMENT_URL' => $arResult['ELEMENT_URL'],

        // настройки кэширования
        'CACHE_TYPE' => $arParams['CACHE_TYPE'],
        'CACHE_TIME' => $arParams['CACHE_TIME'],
        'CACHE_GROUPS' => $arParams['CACHE_GROUPS'],

        // настройки постраничной навигации
        'DISPLAY_TOP_PAGER' => $arParams['DISPLAY_TOP_PAGER'],
        'DISPLAY_BOTTOM_PAGER' => $arParams['DISPLAY_BOTTOM_PAGER'],
        'PAGER_TITLE' => $arParams['PAGER_TITLE'],
        'PAGER_SHOW_ALWAYS' => $arParams['PAGER_SHOW_ALWAYS'],
        'PAGER_TEMPLATE' => $arParams['PAGER_TEMPLATE'],
        'PAGER_DESC_NUMBERING' => $arParams['PAGER_DESC_NUMBERING'],
        'PAGER_DESC_NUMBERING_CACHE_TIME' => $arParams['PAGER_DESC_NUMBERING_CACHE_TIME'],
        'PAGER_SHOW_ALL' => $arParams['PAGER_SHOW_ALL'],
        'PAGER_BASE_LINK_ENABLE' => $arParams['PAGER_BASE_LINK_ENABLE'],
        'PAGER_BASE_LINK' => $arParams['PAGER_BASE_LINK'],
        'PAGER_PARAMS_NAME' => $arParams['PAGER_PARAMS_NAME'],

        // настройки страницы 404 Not Found
        'MESSAGE_404' => $arParams['MESSAGE_404'],
        'SET_STATUS_404' => $arParams['SET_STATUS_404'],
        'SHOW_404' => $arParams['SHOW_404'],
        'FILE_404' => $arParams['FILE_404'],
    ),
    $component
);
?>
<?php
/*
 * Файл local/components/tokmakov/iblock/templates/.default/popular.php
 */
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();

/** @var array $arParams */
/** @var array $arResult */
/** @global CMain $APPLICATION */
/** @global CUser $USER */
/** @global CDatabase $DB */
/** @var CBitrixComponentTemplate $this */
/** @var string $templateName */
/** @var string $templateFile */
/** @var string $templateFolder */
/** @var string $componentPath */
/** @var CBitrixComponent $component */

$this->setFrameMode(true);
?>

<?php
$APPLICATION->IncludeComponent(
    'tokmakov:iblock.popular',
    '',
    Array(
        'IBLOCK_TYPE' => $arParams['IBLOCK_TYPE'],             // тип инфоблока
        'IBLOCK_ID' => $arParams['IBLOCK_ID'],                 // идентификатор инфоблока

        //  использовать символьные коды вместо идентификаторов
        'USE_CODE_INSTEAD_ID' => $arParams['USE_CODE_INSTEAD_ID'],

        'ROOT_SECTIONS' => $arParams['POPULAR_ROOT_SECTIONS'], // показывать корневые разделы?
        'POPULAR_SECTIONS' => $arParams['POPULAR_SECTIONS'],   // из каких разделов выбирать популярные элементы
        'ELEMENT_COUNT' => $arParams['POPULAR_ELEMENT_COUNT'], // макс. кол-во популярных элементов в разделе

        // устанавливать заголовок страницы из названия инфоблока?
        'SET_PAGE_TITLE' => $arParams['POPULAR_SET_PAGE_TITLE'],
        // устанавливать заголовок окна браузера из названия инфоблока?
        'SET_BROWSER_TITLE' => $arParams['POPULAR_SET_BROWSER_TITLE'],

        // URL, ведущий на страницу с содержимым раздела
        'SECTION_URL' => $arResult['SECTION_URL'],
        // URL, ведущий на страницу с содержимым элемента
        'ELEMENT_URL' => $arResult['ELEMENT_URL'],

        // настройки кэширования
        'CACHE_TYPE' => $arParams['CACHE_TYPE'],
        'CACHE_TIME' => $arParams['CACHE_TIME'],
        'CACHE_GROUPS' => $arParams['CACHE_GROUPS'],
    ),
    $component
);
?>

Содержимое остальных файлов не отличается от тех, что уже были рассмотрены ранее. Я лишь добавил в заголовки строку [Комплексный], чтобы было понятно, что используется шаблон комплексного компонента. Если бы этих шаблонов не было, то были бы задействованы шаблоны простых компонентов:

  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.element/.default/template.php является копией local/components/tokmakov/iblock.element/templates/.default/template.php
  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.section/.default/template.php является копией local/components/tokmakov/iblock.section/templates/.default/template.php
  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.popular/.default/template.php является копией local/components/tokmakov/iblock.popular/templates/.default/template.php
  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.element/.default/style.css является копией local/components/tokmakov/iblock.element/templates/.default/style.css
  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.section/.default/style.css является копией local/components/tokmakov/iblock.section/templates/.default/style.css
  • файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.popular/.default/style.css является копией local/components/tokmakov/iblock.popular/templates/.default/style.css

Эти копии как раз и нужны, чтобы настраивать комплексный компонент под свои нужды, не затрагивая шаблоны и стили простых компонентов в их «родных» директориях. Для этих же целей предназначены файлы result_modifier.php и component_epilog.php. Можно изменить результаты работы простых компонентов здесь (т.е. модифицировать массив $arResult) и изменить здесь же представление в браузере (редактируя файлы template.php и style.css). При этом, когда простые компоненты используются «сами по себе», результат их работы и представление этих результатов в браузере останутся без изменений.

Давайте для примера изменим результат работы компонента tokmakov:iblock.popular и добавим в массив $arResult информацию о подразделах корневых разделов. Сейчас массив $arResult выглядит так:

Array
(
    [IBLOCK] => Array
        (
            [ID] => 5
            [IBLOCK_TYPE_ID] => content
            [CODE] => articles
            [NAME] => Статьи о домашних животных
            ..........
        )
    [ROOT_SECTIONS] => Array
        (
            [0] => Array
                (
                    [ID] => 28
                    [NAME] => Породы собак
                    [SECTION_PAGE_URL] => /demo/category/id/28/
                    [CODE] => porody-sobak
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                )
            [1] => Array
                (
                    [ID] => 29
                    [NAME] => Породы кошек
                    [SECTION_PAGE_URL] => /demo/category/id/29/
                    [CODE] => porody-koshek
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                )
        )
    [POPULAR_SECTIONS] => Array
        (
            [0] => Array
                (
                    [ID] => 28
                    [NAME] => Породы собак
                    [SECTION_PAGE_URL] => /demo/category/id/28/
                    [CODE] => porody-sobak
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                    [ITEMS] => Array
                        (
                            ..........
                        )
                )
            [1] => Array
                (
                    [ID] => 29
                    [NAME] => Породы кошек
                    [SECTION_PAGE_URL] => /demo/category/id/29/
                    [CODE] => porody-koshek
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                    [ITEMS] => Array
                        (
                            ..........
                        )
                )
        )
)

Создаем файл result_modifier.php следующего содержания:

<?php
/*
 * Файл local/components/tokmakov/iblock/templates/.default/tokmakov/iblock.popular/default/result_modifier.php
 */

/*
 * Выбираем подразделы корневых разделов инфоблока
 */
if (empty($arResult['ROOT_SECTIONS'])) {
    return;
}

// какие поля подразделов выбираем
$arSelect = array(
    'ID',
    'NAME',
    'SECTION_PAGE_URL'
);
// условия выборки подразделов
$arFilter = array(
    'IBLOCK_ID' => $arResult['ID'], // идентификатор инфоблока
    'IBLOCK_ACTIVE' => 'Y',         // инфоблок должен быть активен
    'ACTIVE' => 'Y',                // только активные подразделы
    'CHECK_PERMISSIONS' => 'Y',     // проверять права доступа
);
// сортировка
$arSort = array(
    'SORT' => 'ASC',
);
// перебираем все корневые разделы, для каждого получаем подразделы
foreach ($arResult['ROOT_SECTIONS'] as &$arRoot) {
    $arFilter['SECTION_ID'] = $arRoot['ID'];
    $rsChilds = CIBlockSection::GetList($arSort, $arFilter, false, $arSelect);
    // устанавливаем шаблон пути для подразделов, вместо того,
    // который указан в настройках информационного блока
    $rsChilds->SetUrlTemplates('', $arParams['SECTION_URL']);
    while ($arChild = $rsChilds->GetNext()) {
        $arRoot['CHILD_SECTIONS'][] = $arChild;
    }
}
unset($arRoot);

Теперь массив $arResult выглядит так:

Array
(
    [IBLOCK] => Array
        (
            [ID] => 5
            [IBLOCK_TYPE_ID] => content
            [CODE] => articles
            [NAME] => Статьи о домашних животных
            ..........
        )
    [ROOT_SECTIONS] => Array
        (
            [0] => Array
                (
                    [ID] => 28
                    [NAME] => Породы собак
                    [SECTION_PAGE_URL] => /demo/category/id/28/
                    [CODE] => porody-sobak
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                    [CHILD_SECTIONS] => Array
                        (
                            [0] => Array
                                (
                                    [ID] => 30
                                    [NAME] => Служебные породы
                                    [SECTION_PAGE_URL] => /demo/category/id/30/
                                    [CODE] => sluzhebnye-porody
                                    [IBLOCK_TYPE_ID] => content
                                    [IBLOCK_ID] => 5
                                    [IBLOCK_CODE] => articles
                                    ..........
                                )
                            [1] => Array
                                (
                                    [ID] => 31
                                    [NAME] => Декоративные породы
                                    [SECTION_PAGE_URL] => /demo/category/id/31/
                                    [CODE] => dekorativnye-porody
                                    [IBLOCK_TYPE_ID] => content
                                    [IBLOCK_ID] => 5
                                    [IBLOCK_CODE] => articles
                                    ..........
                                )
                        )
                )
            [1] => Array
                (
                    [ID] => 29
                    [NAME] => Породы кошек
                    [SECTION_PAGE_URL] => /demo/category/id/29/
                    [CODE] => porody-koshek
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                )
        )
    [POPULAR_SECTIONS] => Array
        (
            [0] => Array
                (
                    [ID] => 28
                    [NAME] => Породы собак
                    [SECTION_PAGE_URL] => /demo/category/id/28/
                    [CODE] => porody-sobak
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                    [ITEMS] => Array
                        (
                            ..........
                        )
                )
            [1] => Array
                (
                    [ID] => 29
                    [NAME] => Породы кошек
                    [SECTION_PAGE_URL] => /demo/category/id/29/
                    [CODE] => porody-koshek
                    [IBLOCK_TYPE_ID] => content
                    [IBLOCK_ID] => 5
                    [IBLOCK_CODE] => articles
                    ..........
                    [ITEMS] => Array
                        (
                            ..........
                        )
                )
        )
)

Пример вызова комплексного компонента:

<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");
$APPLICATION->SetTitle("Статьи о домашних животных");
?>

<?php
$APPLICATION->IncludeComponent(
    "tokmakov:iblock",
    "",
    Array(
        "ADD_SECTIONS_CHAIN" => "Y",
        "CACHE_GROUPS" => "Y",
        "CACHE_TIME" => "3600",
        "CACHE_TYPE" => "A",
        "DETAIL_SET_BROWSER_TITLE" => "Y",
        "DETAIL_SET_META_DESCRIPTION" => "Y",
        "DETAIL_SET_META_KEYWORDS" => "Y",
        "DETAIL_SET_PAGE_TITLE" => "Y",
        "DISPLAY_BOTTOM_PAGER" => "Y",
        "DISPLAY_TOP_PAGER" => "N",
        "FILE_404" => "",
        "IBLOCK_ID" => "5",
        "IBLOCK_TYPE" => "content",
        "MESSAGE_404" => "",
        "PAGER_BASE_LINK_ENABLE" => "N",
        "PAGER_DESC_NUMBERING" => "N",
        "PAGER_DESC_NUMBERING_CACHE_TIME" => "36000",
        "PAGER_SHOW_ALL" => "N",
        "PAGER_SHOW_ALWAYS" => "N",
        "PAGER_TEMPLATE" => ".default",
        "PAGER_TITLE" => "Элементы",
        "POPULAR_ELEMENT_COUNT" => "4",
        "POPULAR_ROOT_SECTIONS" => "Y",
        "POPULAR_SECTIONS" => array(),
        "POPULAR_SET_BROWSER_TITLE" => "Y",
        "POPULAR_SET_PAGE_TITLE" => "Y",
        "SECTION_ELEMENT_COUNT" => "3",
        "SECTION_SET_BROWSER_TITLE" => "Y",
        "SECTION_SET_META_DESCRIPTION" => "Y",
        "SECTION_SET_META_KEYWORDS" => "Y",
        "SECTION_SET_PAGE_TITLE" => "Y",
        "SEF_FOLDER" => "/demo/",
        "SEF_MODE" => "Y",
        "SEF_URL_TEMPLATES" => array(
            "element"=>"item/id/#ELEMENT_ID#/",
            "popular"=>"",
            "section"=>"category/id/#SECTION_ID#/"
        ),
        "SET_STATUS_404" => "Y",
        "SHOW_404" => "Y"
    )
);
?>

<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");
?>

В браузере наш компонент будет выглядеть примерно так:

Поиск: CMS • Web-разработка • Битрикс • Инфоблок • Компонент • Раздел инфоблока • Шаблон компонента • Элемент инфоблока

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.