Вадим Интерактивный
Разработчик на Битриксе

Пишем свой компонент

Здравствуйте!
Сегодня мы поговорим про компоненты, их структуру и напишем свой простенький компонент.

Итак, компонент - это логически завершённый код, предназначенный для извлечения информации из инфоблоков и других источников и преобразования её в HTML-код для отображения в виде фрагментов web-страниц. Состоит из собственно компонента (контроллер) и шаблона (представление). Компонент, с помощью API одного или нескольких модулей, манипулирует данными. Шаблон компонента выводит данные на страницу.

Данное определение взято с официальной документации 1С-Битрикс.

Грубо говоря, компонент - это определенный набор файлов.
Структура компонента достаточно хорошо изложена в официальной документации 1С-Битрикс, вот ссылки:

Комплексный компонент - это компонент, как правило формирующий определенный раздел сайта (например каталог) и включающий в себя другие компоненты, об этом вы можете почитать, перейдя по ссылке выше.

Итак, классическая схема работы компонента:


В приложениях статьи вы можете скачать архив компонента-пустышки, в нем содержится минимальный набор файлов для работы.
А также простенький компонент-приветствие, изучить который вы уже сможете самостоятельно после прочтения этой статьи.

Кратко: 
  1. Файл .description.php - описание компонента, примерное содержание файла:
    <?
    if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
    
    $arComponentDescription = array(
    	'NAME' => 'Имя',
    	'DESCRIPTION' => 'Описание',
    	'ICON' => '/images/icon.gif',
    	'SORT' => 90,
    	'CACHE_PATH' => 'Y',
    	'PATH' => array(
    		'ID' => 'new_path',
    		'NAME' => 'Тестовый раздел'
    	),
    );
    ?>
    Здесь подробно описаны все ключи массива $arComponentDescription
  2. В файле .parameters.php описаны все параметры компонента, отображаемые при редактировании настроек компонента в режиме правки. Однако вы можете передать любой неописанный параметр и компонент его съест (если конечно это учтено в коде компонента), но если есть возмоность описать параметр в этом файле, то лучше так и сделать. Примерное содержание файла:
    <?
    if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
    
    if(!CModule::IncludeModule('iblock'))
    	return;
    
    $arTypesEx = CIBlockParameters::GetIBlockTypes(Array('-'=>' '));
    
    $arIBlocks=Array();
    $db_iblock = CIBlock::GetList(Array('SORT'=>'ASC'), Array('SITE_ID'=>$_REQUEST['site'], 'TYPE' => ($arCurrentValues['IBLOCK_TYPE']!='-'?$arCurrentValues['IBLOCK_TYPE']:'')));
    while($arRes = $db_iblock->Fetch())
    	$arIBlocks[$arRes['ID']] = $arRes['NAME'];
    
    $arComponentParameters = array(
    	'GROUPS' => array(
    	),
    	'PARAMETERS' => array(
    		
    		'STRING_PARAM' => array(
    			'PARENT' => 'BASE',
    			'NAME' => 'Строка',
    			'TYPE' => 'STRING',
    			'DEFAULT' => '',
    		),
    		'IBLOCK_TYPE' => Array(
    			'PARENT' => 'BASE',
    			'NAME' => 'Тип информационного блока (используется только для проверки)',
    			'TYPE' => 'LIST',
    			'VALUES' => $arTypesEx,
    			'DEFAULT' => 'news',
    			'REFRESH' => 'Y',
    		),
    		'IBLOCK_ID' => Array(
    			'PARENT' => 'BASE',
    			'NAME' => 'Код информационного блока',
    			'TYPE' => 'LIST',
    			'VALUES' => $arIBlocks,
    			'DEFAULT' => '',
    			'ADDITIONAL_VALUES' => 'Y',
    			'REFRESH' => 'Y',
    		),
    		'LIST_PARAM' => array(
    			'PARENT' => 'BASE',
    			'NAME' => 'Список',
    			'TYPE' => 'LIST',
    			'MULTIPLE' => 'Y',
    			'VALUES' => array(5 => 'a', 6 => 'b', 7 => 'c'),
    		),
    		'CHECKBOX_PARAM' => array(
    			'PARENT' => 'BASE',
    			'NAME' => 'Галочка',
    			'TYPE' => 'CHECKBOX',
    			'VALUE' => 'N',
    			'REFRESH' => 'N',
    		),
    		'DETAIL_URL' => CIBlockParameters::GetPathTemplateParam(
    			'DETAIL',
    			'DETAIL_URL',
    			'URL для детальной страницы',
    			'',
    			'URL_TEMPLATES'
    		),
    		'ACTIVE_DATE_FORMAT' => CIBlockParameters::GetDateFormat('Формат даты', 'ADDITIONAL_SETTINGS'),
    		
    		'CACHE_TIME'  =>  Array('DEFAULT'=>3600),
    	),
    );
    ?>
    Здесь подробно описаны все ключи массива $arComponentParameters
  3. Файл component.php - содержит код компонента, примерное содержание файла:
    <?
    if(!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
    
    $arResult = array();
    
    // Старт кеша 
    // если кеша нет, то выполняет код, заключенный в фигурные скобки,
    // в противном случае вместо этой части компонента подгружается кеш.
    if ($this->StartResultCache(false, false)) {
    	CModule::IncludeModule('iblock');
    	
    	// Кешируемый код компонента
    	
    	// Подключение шаблона
    	$this->IncludeComponentTemplate(); 
    }
    
    // Код, выполняющийся вне зависимости от кеша
    ?>
    Частые ошибки и замечания:
    • Шаблон компонента (template.php, который будет рассмотрен чуть позже) кешируется. Поэтому использовать в нем отложенные функции типа $APPLICATION->SetTitle() не стоит, т.к. срабатывать они будут только при отсутствии кеша.
    • Кешируются и передаются в шаблон только массивы данных $arResult и $arParams, все вспомогательные массивы, используемые в компоненте, не передаются далее.
    • Все изменения $arResult, $arParams и вывод после вызова метода $this->IncludeComponentTemplate() подключения шаблона не будут сохранены в кеш.
    Настоятельно советую прочитать статью про кеш.
  4. Папка images - папка с картинками компонента
  5. Папка templates - папка с шаблонами компонента
    1. .default - название шаблона компонента
      1. файл template.php - html шаблон компонента, примерное содержание файла:
        <div>
        	<b><?=$arResult['HELLO_TEXT'];?></b>
        </div>
        Рекомендую прочитать статью про шаблоны. Обратите внимание на пункт «Переменные, доступные в шаблоне компонента» в статье, это интересно.
      2. файл result_modifier.php, в котором можно модифициовать массив $arResult. Он подключается сразу после вызова component.php и до вызова template.php, примерное содержание файла:
        if(!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
        $arResult['HELLO_TEXT'] .= ' Какая завтра погода?';
        Про result_modifier.php.
      3. И вот мы добрались до файла component_epilog.php, он подключается после template.php и не кешируется. Кроме того он может содержать не все данные из $arResult.
        Дело в том, что в компоненте может быть вызвана функция $this->SetResultCacheKeys(), содержащая массив ключей, которые стоит кешировать и именно с этими ключами работает component_epilog.php.
        Если функция $this->SetResultCacheKeys() не используется, то в файл кеша попадают все значения массива $arResult. Однако, что делать, если эта функция используется в стандартном компоненте, а в component_epilog.php нам необходимо передать какой-либо ключ, не описанный в этой фунции?
        Все очень просто, необходио добавить следующую строку в result_modifier.php:
        $this->__component->SetResultCacheKeys(array('ELEMENTS')); // Добавляет ключ ELEMENTS массива $arResult в кеширование
        component_epilog.php как правило используют для дополнения компонента логикой, которая не должна быть закеширована (например вызов отложенной функции $APPLICATION->SetTitle), примерное содержание файла:
        if(!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED!==true) die();
        $APPLICATION->SetTitle($arResult['HELLO_TEXT']);
        Про component_epilog.php.

На этом все, спасибо за внимание!