Битрикс. Создание комплексного компонента. Часть 1 из 4
17.09.2018
Теги: CMS • Web-разработка • Битрикс • Инфоблок • Компонент • РазделИнфоблока • ШаблонКомпонента • ЭлементИнфоблока
Комплексный компонент служит для организации целого раздела сайта (форум, каталог). Для вывода данных он подключает простые компоненты. По сути, является контроллером простых компонентов. Комплексный компонент определяет на основании HTTP запроса страницу, которую требуется показать, и подключает шаблон этой страницы.
Давайте создадим три простых компонента и объединим их в комплексный. Этот комплексный компонент будет уметь показывать содержимое инфоблока. Инфоблок включает в себя элементы и разделы. Значит, наш комплексный компонент должен уметь:
- показывать элемент инфоблока, простой компонент
tokmakov:iblock.element
- показывать раздел инфоблока, простой компонент
tokmakov:iblock.section
- показывать главную страницу инфоблока, простой компонент
tokmakov:iblock.popular
Создадим внутри папки /local/
такую структуру:
[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
[iblock.element]
[templates]
[.default]
template.php
style.css
.description.php
.parameters.php
component.php
[iblock.section]
[templates]
[.default]
template.php
style.css
.description.php
.parameters.php
component.php
[iblock.popular]
[templates]
[.default]
template.php
style.css
.description.php
.parameters.php
component.php
lang
. Так что, если нужен комплексный компонент «по фен-шуй» — сделайте это сами. Лично я сомневаюсь, что Битрикс со своим г…но-кодом когда-нибудь выйдет на международный уровень.
Красным цветом выделено все, что относится к комплексному компоненту, а зеленым выделены три простых компонента.
Простой компонент tokmakov:iblock.element
Выводит детальную информацию об элементе инфоблока: заголовок, детальную картинку, количество просмотров, детальное описание. В браузере это выглядит примерно так:
<?php /* * Файл local/components/tokmakov/iblock.element/.description.php */ if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die(); $arComponentDescription = array( 'NAME' => 'Элемент инфоблока', // название компонента 'DESCRIPTION' => 'Выводит детальную страницу элемента инфоблока', 'ICON' => '/images/icon.gif', // иконка компонента относительно папки компонента 'CACHE_PATH' => 'Y', // показывать кнопку очистки кеша 'SORT' => 30, // порядок сортировки в визуальном редакторе 'COMPLEX' => 'N', // признак комплексного компонента 'PATH' => array( // расположение компонента в визуальном редакторе 'ID' => 'other_components', // идентификатор верхнего уровеня в редакторе 'NAME' => 'Прочие компоненты', // название верхнего уровня в редакторе 'CHILD' => array( // второй уровень в визуальном редакторе 'ID' => 'other_iblock', // идентификатор второго уровня в редакторе 'NAME' => 'Информационный блок' // название второго уровня в редакторе ) ) );
<?php /* * Файл local/components/tokmakov/iblock.element/.parameters.php */ if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die(); // проверяем, установлен ли модуль «Информационные блоки»; если да — то подключаем его if (!CModule::IncludeModule('iblock')) { return; } /* * Получаем массив всех типов инфоблоков — для возможности выбора */ $arIBlockType = 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']; } /* * Настройки компонента */ $arComponentParameters = array( 'GROUPS' => array( // кроме групп по умолчанию, добавляем свою группу настроек 'SEO_SETTINGS' => array( 'NAME' => 'Настройки SEO', 'SORT' => 800 ), ), 'PARAMETERS' => array( // выбор типа инфоблока 'IBLOCK_TYPE' => array( 'PARENT' => 'BASE', 'NAME' => 'Выберите тип инфоблока', 'TYPE' => 'LIST', 'VALUES' => $arIBlockType, 'REFRESH' => 'Y', ), // выбор самого инфоблока 'IBLOCK_ID' => array( 'PARENT' => 'BASE', 'NAME' => 'Выберите инфоблок', 'TYPE' => 'LIST', 'VALUES' => $arInfoBlocks, ), // идентификатор элемента получать из $_REQUEST["ELEMENT_ID"] 'ELEMENT_ID' => array( 'PARENT' => 'BASE', 'NAME' => 'Идентификатор элемента', 'TYPE' => 'STRING', 'DEFAULT' => '={$_REQUEST["ELEMENT_ID"]}', ), // символьный код элемента получать из $_REQUEST["ELEMENT_CODE"] 'ELEMENT_CODE' => array( 'PARENT' => 'BASE', 'NAME' => 'Символьный код элемента', 'TYPE' => 'STRING', 'DEFAULT' => '={$_REQUEST["ELEMENT_CODE"]}', ), // использовать символьный код вместо ID; если отмечен этот checkbox, // в визуальном редакторе надо будет обязательно изменить SECTION_URL // и ELEMENT_URL, чтобы вместо #SECTION_ID# и #ELEMENT_ID# в шаблонах // ссылок использовались #SECTION_CODE# и #ELEMENT_CODE# 'USE_CODE_INSTEAD_ID' => array( 'PARENT' => 'URL_TEMPLATES', 'NAME' => 'Использовать символьный код вместо ID', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'N', ), // шаблон ссылки на страницу раздела 'SECTION_URL' => array( 'PARENT' => 'URL_TEMPLATES', 'NAME' => 'URL, ведущий на страницу с содержимым раздела', 'TYPE' => 'STRING', 'DEFAULT' => 'category/id/#SECTION_ID#/' ), // шаблон ссылки на страницу элемента 'ELEMENT_URL' => array( 'PARENT' => 'URL_TEMPLATES', 'NAME' => 'URL, ведущий на страницу с содержимым элемента', 'TYPE' => 'STRING', 'DEFAULT' => 'item/id/#ELEMENT_ID#/' ), // SEO-настройки 'SET_PAGE_TITLE' => array( 'PARENT' => 'SEO_SETTINGS', 'NAME' => 'Устанавливать заголовок страницы', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), 'SET_BROWSER_TITLE' => array( 'PARENT' => 'SEO_SETTINGS', 'NAME' => 'Устанавливать заголовок окна браузера', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), 'SET_META_KEYWORDS' => array( 'PARENT' => 'SEO_SETTINGS', 'NAME' => 'Устанавливать мета-тег keywords', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), 'SET_META_DESCRIPTION' => array( 'PARENT' => 'SEO_SETTINGS', 'NAME' => 'Устанавливать мета-тег description', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), // включать раздел в цепочку навигации? 'ADD_SECTIONS_CHAIN' => Array( 'PARENT' => 'ADDITIONAL_SETTINGS', 'NAME' => 'Включать раздел в цепочку навигации', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), // настройки кэширования 'CACHE_TIME' => array('DEFAULT'=>3600), 'CACHE_GROUPS' => array( 'PARENT' => 'CACHE_SETTINGS', 'NAME' => 'Учитывать права доступа', 'TYPE' => 'CHECKBOX', 'DEFAULT' => 'Y', ), ), ); // добавляем еще одну настройку — на случай, если элемент инфоблока не найден CIBlockParameters::Add404Settings($arComponentParameters, $arCurrentValues);
USE_CODE_INSTEAD_ID
. Если он не задан, элемент инфоблока будет получен по идентификатору. В противном случае — по символьному коду. Это сделано для того, чтобы избежать дублирования, когда одна и та же страница доступна по двум адресам. Внимательно следите за значением этого параметра, чтобы не получить 404 Not Found.
<?php /* * Файл local/components/tokmakov/iblock.element/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 (!CModule::IncludeModule('iblock')) { ShowError('Модуль «Информационные блоки» не установлен'); return; } if (!isset($arParams['CACHE_TIME'])) { $arParams['CACHE_TIME'] = 3600; } // тип инфоблока $arParams['IBLOCK_TYPE'] = trim($arParams['IBLOCK_TYPE']); // идентификатор инфоблока $arParams['IBLOCK_ID'] = intval($arParams['IBLOCK_ID']); // если получено некорректное значение идентификатора элемента или символьного // кода элемента инфоблока, показываем страницу 404 Not Found $notFound = false; if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // символьный код элемента инфоблока $arParams['ELEMENT_CODE'] = empty($arParams['ELEMENT_CODE']) ? '' : trim($arParams['ELEMENT_CODE']); if (empty($arParams['ELEMENT_CODE'])) { $notFound = true; } } else { // идентификатор элемента инфоблока $arParams['ELEMENT_ID'] = empty($arParams['ELEMENT_ID']) ? 0 : intval($arParams['ELEMENT_ID']); if (empty($arParams['ELEMENT_ID'])) { $notFound = true; } } 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; } // шаблон ссылки на страницу с содержимым раздела $arParams['SECTION_URL'] = trim($arParams['SECTION_URL']); // шаблон ссылки на страницу с содержимым элемента $arParams['ELEMENT_URL'] = trim($arParams['ELEMENT_URL']); if ($this->StartResultCache(false, ($arParams['CACHE_GROUPS']==='N' ? false: $USER->GetGroups()))) { if ($arParams['USE_CODE_INSTEAD_ID'] == 'Y') { // работаем с символьным кодом элемента $ELEMENT_ID = CIBlockFindTools::GetElementID( // получаем идентификатор по символьному коду 0, // идентификатор элемента мы не знаем $arParams['ELEMENT_CODE'], // символьный код элемента false, // идентификатор раздела false, // символьный код раздела array( 'IBLOCK_ACTIVE' => 'Y', 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ACTIVE' => 'Y', 'ACTIVE_DATE' => 'Y', 'SECTION_GLOBAL_ACTIVE' => 'Y', 'CHECK_PERMISSIONS' => 'Y', ) ); } else { // работаем с идентификатором элемента $ELEMENT_ID = $arParams['ELEMENT_ID']; } if ($ELEMENT_ID) { // какие поля элемента инфоблока выбираем $arSelect = array( 'ID', // идентификатор элемента 'CODE', // символьный код элемента 'IBLOCK_ID', // идентификатор инфоблока 'IBLOCK_SECTION_ID', // идентификатор раздела элемента 'SECTION_PAGE_URL', // URL страницы раздела элемента 'NAME', // название этого элемента 'DETAIL_PICTURE', // детальная картинка элемента 'DETAIL_TEXT', // детальное описание элемента 'DETAIL_PAGE_URL', // URL страницы этого элемента 'SHOW_COUNTER', // количество просмотров элемента 'PROPERTY_*', // пользовательские свойства ); // условия выборки элемента инфоблока $arFilter = array( 'IBLOCK_ID' => $arParams['IBLOCK_ID'], // идентификатор инфоблока 'IBLOCK_ACTIVE' => 'Y', // инфоблок должен быть активен 'ID' => $ELEMENT_ID, // идентификатор элемента инфоблока 'ACTIVE' => 'Y', // выбираем только активные элементы 'ACTIVE_DATE' => 'Y', // фильтр по датам активности 'SECTION_GLOBAL_ACTIVE' => 'Y', // фильтр по активности всех родителей 'CHECK_PERMISSIONS' => 'Y', // проверка прав доступа ); if ($arParams['SECTION_ID']) { $arFilter['SECTION_ID'] = $arParams['SECTION_ID']; } elseif ($arParams['SECTION_CODE']) { $arFilter['SECTION_CODE'] = $arParams['SECTION_CODE']; } // выполняем запрос к базе данных $rsElement = CIBlockElement::GetList( array(), // сортировка $arFilter, // фильтр false, // группировка false, // постраничная навигация $arSelect // поля ); // устанавливаем шаблоны путей для раздела и элемента, вместо тех, // которые указаны в настройках информационного блока $rsElement->SetUrlTemplates($arParams['ELEMENT_URL'], $arParams['SECTION_URL']); if ($obElement = $rsElement->GetNextElement()) { $arResult = $obElement->GetFields(); // пользовательские свойства $arResult['PROPERTIES'] = $obElement->GetProperties(); // получаем значения пользовательских свойст в удобном для отображения виде foreach ($arResult['PROPERTIES'] as $code => $data) { $arResult['DISPLAY_PROPERTIES'][$code] = CIBlockFormatProperties::GetDisplayValue($arResult, $data, ''); } /* * Добавляем в массив arResult дополнительные элементы, которые могут потребоваться в шаблоне */ // получаем SEO-свойства выбранного элемента $ipropValues = new \Bitrix\Iblock\InheritedProperty\ElementValues( $arResult['IBLOCK_ID'], $arResult['ID'] ); $arResult['IPROPERTY_VALUES'] = $ipropValues->getValues(); if (isset($arResult['DETAIL_PICTURE'])) { // получаем данные картинки элемента $arResult['DETAIL_PICTURE'] = (0 < $arResult['DETAIL_PICTURE'] ? CFile::GetFileArray($arResult['DETAIL_PICTURE']) : false); if ($arResult['DETAIL_PICTURE']) { $arResult['DETAIL_PICTURE']['ALT'] = $arResult['IPROPERTY_VALUES']['ELEMENT_DETAIL_PICTURE_FILE_ALT']; if ($arResult['DETAIL_PICTURE']['ALT'] == '') { $arResult['DETAIL_PICTURE']['ALT'] = $arResult['NAME']; } $arResult['DETAIL_PICTURE']['TITLE'] = $arResult['IPROPERTY_VALUES']['ELEMENT_DETAIL_PICTURE_FILE_TITLE']; if ($arResult['DETAIL_PICTURE']['TITLE'] == '') { $arResult['DETAIL_PICTURE']['TITLE'] = $arResult['NAME']; } } } // получаем данные о родительском разделе инфоблока $arSectionFilter = array( 'IBLOCK_ID' => $arResult['IBLOCK_ID'], 'ID' => $arResult['IBLOCK_SECTION_ID'], 'ACTIVE' => 'Y', ); // выполняем запрос к базе данных $rsSection = CIBlockSection::GetList(array(), $arSectionFilter); // устанавливаем шаблон пути для раздела, вместо того, // который указан в настройках информационного блока $rsSection->SetUrlTemplates('', $arParams['SECTION_URL']); if ($arResult['SECTION'] = $rsSection->GetNext()) { // путь к элементу от корня $arResult['SECTION']['PATH'] = array(); // если нужно добавить раздел в цепочку навигации — получаем всех родителей if ($arParams['ADD_SECTIONS_CHAIN'] == 'Y') { $rsPath = CIBlockSection::GetNavChain( $arResult['SECTION']['IBLOCK_ID'], $arResult['SECTION']['ID'], array( 'ID', 'NAME', 'SECTION_PAGE_URL' ) ); $rsPath->SetUrlTemplates('', $arParams['SECTION_URL']); while ($arPath = $rsPath->GetNext()) { $arResult['SECTION']['PATH'][] = $arPath; } } } } } if (isset($arResult['ID'])) { $this->SetResultCacheKeys( array( 'ID', 'NAME', 'IPROPERTY_VALUES' ) ); $this->IncludeComponentTemplate(); } else { $this->AbortResultCache(); \Bitrix\Iblock\Component\Tools::process404( trim($arParams['MESSAGE_404']) ?: 'Элемент инфоблока не найден', true, $arParams['SET_STATUS_404'] === 'Y', $arParams['SHOW_404'] === 'Y', $arParams['FILE_404'] ); } } // кэш не затронет все действия ниже, здесь работаем уже с другим $arResult if (isset($arResult['ID'])) { // счетчик просмотров элемента CIBlockElement::CounterInc($arResult['ID']); if ($arParams['SET_PAGE_TITLE'] == 'Y') { // установить заголовок страницы? if ($arResult['IPROPERTY_VALUES']['ELEMENT_PAGE_TITLE'] != '') { $APPLICATION->SetTitle($arResult['IPROPERTY_VALUES']['ELEMENT_PAGE_TITLE']); } else { $APPLICATION->SetTitle($arResult['NAME']); } } if ($arParams['SET_BROWSER_TITLE'] == 'Y') { // установить заголовок окна браузера? if ($arResult['IPROPERTY_VALUES']['ELEMENT_META_TITLE'] != '') { $APPLICATION->SetPageProperty('title', $arResult['IPROPERTY_VALUES']['ELEMENT_META_TITLE']); } else { $APPLICATION->SetPageProperty('title', $arResult['NAME']); } } // установить мета-тег keywords? if ($arParams['SET_META_KEYWORDS'] == 'Y' && $arResult['IPROPERTY_VALUES']['ELEMENT_META_KEYWORDS'] != '') { $APPLICATION->SetPageProperty('keywords', $arResult['IPROPERTY_VALUES']['ELEMENT_META_KEYWORDS']); } // установить мета-тег description? if ($arParams['SET_META_DESCRIPTION'] == 'Y' && $arResult['IPROPERTY_VALUES']['ELEMENT_META_DESCRIPTION'] != '') { $APPLICATION->SetPageProperty('description', $arResult['IPROPERTY_VALUES']['ELEMENT_META_DESCRIPTION']); } // добавить раздел в цепочку навигации? if ($arParams['ADD_SECTIONS_CHAIN'] == 'Y' && !empty($arResult['SECTION']['PATH'])) { foreach ($arResult['SECTION']['PATH'] as $arPath) { $APPLICATION->AddChainItem($arPath['NAME'], $arPath['~SECTION_PAGE_URL']); } } return $arResult['ID']; }
bool CBitrixComponent::StartResultCache( int cacheTime, string additionalCacheID, string cachePath )
Метод поддержки внутреннего кеширования компонента. Возвращает true
в случае, если кеш недействителен, или false
в противном случае.
Если кеш действителен, метод отправляет на экран его содержимое, заполняет $arResult
и возвращает false
. Если кеш недействителен, метод возвращает true
, кеширование завершается и кеш сохраняется при вызове методов
CBitrixComponent::IncludeComponentTemplate()
- или
CBitrixComponent::ShowComponentTemplate()
сразу после подключения шаблона компонента.
Параметры
cacheTime
— Время кеширования в секундах. Если этот параметр равенfalse
, то время кеширования берется из входного параметра$arParams['CACHE_TIME']
. Необязательный.additionalCacheID
— Кеш зависит от текущего сайта (SITE_ID
), имени компонента, имени шаблона, входных параметров$arParams
. Если кеш должен зависеть от каких-либо дополнительных параметров, то их необходимо передать сюда в виде строки. По умолчанию параметр равенfalse
, т.е. кеш зависит только от текущего сайтаSITE_ID
, имени компонента, имени шаблона и входных параметров$arParams
. Необязательный.cachePath
— Путь к файлу кеша относительно папки кешей. Необязательный.
<?php /* * Файл local/components/tokmakov/iblock.element/templates/.default/template.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(false); ?> <h1><?= $arResult['NAME']; ?></h1> <article id="iblock-element"> <?php if (!empty($arResult['DETAIL_PICTURE'])): ?> <img src="<?= $arResult['DETAIL_PICTURE']['SRC']; ?>" alt="<?= $arResult['DETAIL_PICTURE']['ALT']; ?>" title="<?= $arResult['DETAIL_PICTURE']['TITLE']; ?>" /> <?php endif; ?> <p>Количество просмотров: <?= $arResult['SHOW_COUNTER'] ? $arResult['SHOW_COUNTER'] : 0; ?></p> <?php if (!empty($arResult['DETAIL_TEXT'])): ?> <div> <?= $arResult['DETAIL_TEXT']; ?> </div> <?php endif; ?> <p><a href="<?= $arResult['SECTION']['SECTION_PAGE_URL']; ?>">Назад в раздел</a></p> </article>
/*
* Файл local/components/tokmakov/iblock.element/templates/.default/style.css
*/
#iblock-element {
}
Создадим раздел /demo/
и разместим на странице /demo/index.php
вызов компонента:
<?php require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); $APPLICATION->SetTitle("Статьи о домашних животных"); ?> <?php $APPLICATION->IncludeComponent( "tokmakov:iblock.element", "", Array( "ADD_SECTIONS_CHAIN" => "Y", "CACHE_GROUPS" => "Y", "CACHE_TIME" => "3600", "CACHE_TYPE" => "A", "ELEMENT_CODE" => $_REQUEST["ELEMENT_CODE"], "ELEMENT_ID" => $_REQUEST["ELEMENT_ID"], "ELEMENT_URL" => "item/id/#ELEMENT_ID#/", "FILE_404" => "", "IBLOCK_ID" => "5", "IBLOCK_TYPE" => "content", "MESSAGE_404" => "", "SECTION_URL" => "category/id/#SECTION_ID#/", "SET_BROWSER_TITLE" => "Y", "SET_META_DESCRIPTION" => "Y", "SET_META_KEYWORDS" => "Y", "SET_PAGE_TITLE" => "Y", "SET_STATUS_404" => "Y", "SHOW_404" => "Y", "USE_CODE_INSTEAD_ID" => "N" ) ); ?> <?php require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php"); ?>
- Битрикс. Создание комплексного компонента. Часть 4 из 4
- Битрикс. Создание комплексного компонента. Часть 3 из 4
- Битрикс. Создание комплексного компонента. Часть 2 из 4
- Битрикс. Работа с инфоблоками в старом ядре
- Битрикс. Работа с инфоблоками в новом ядре
- Битрикс. Работа с шаблонами SEO
- Битрикс. Создание простого компонента. Часть 2 из 2
Поиск: CMS • Web-разработка • Битрикс • Инфоблок • Компонент • Раздел инфоблока • Шаблон компонента • Элемент инфоблока