18 июня 2018

Урок 15. Поддержка классов в компонентах Битрикс

Приветствую! Совсем недавно я рассмотрел разработку собственного универсального компонента Битрикс. Но он был написан ещё по старым канонам разработки. А новое ядро D7 наступает и помаленьку вытесняет старые подходы. Сейчас уже компоненты раздела bitrix:catalog почти все написаны на классах. Я решил так же разобраться в этой теме и переписать свой компонент на новую технологию с использованием классов.

Что меняется при данном подходе? Весь набор фалов остается прежним добавляется только файл class.php, в котором и будет располагаться вся логика.
  • component.php  - уже не обязательный файл
  • class.php - основной фал компонента с классами в котором реализуется вся логика работы компонента на API Bitrix
  • .description.php - файл описания компонента.
  • .parameters.php - файл параметров компонента.
  • templates/.default/template.php - файл шаблона по умолчанию для компонента.
Файл component.php, в таком подходе становится не обязательным. И я не буду его использовать.

Как работает файл class.php?

Как я уже сказал подключается он автоматически. Далее необходимо объявить класс с произвольным именем, как класс наследник от CBitrixComponent.

Код:
class CIblocList extends CBitrixComponent
{

В этом классе уже доступны две переменные (объявлять их не нужно): 
Код:
$this->arParams
$this->arResult

С ними и происходит вся работа, как и при старом подходе.

Так же есть 2 предопределенных метода, которые срабатывают автоматически.
Код:
public function onPrepareComponentParams($arParams) {}
public function executeComponent()

Вызываются они в порядке следования. В функции onPrepareComponentParams() принято обрабатывать массив $arParams. А метод executeComponent() выполняет основной код компонента в котором происходит заполнение массива $this->arResult.
В своем компоненте я разместил следующий код в методе executeComponent().

Код:
public function executeComponent()
{
try
{
$this->checkModules();
$this->getResult();
$this->includeComponentTemplate();
}
catch (SystemException $e)
{
ShowError($e->getMessage());
}
}

Думаю теперь все понятнее стало. Рассмотрим вызов функций по порядку:
  1. $this->checkModules() - мы проверяем подключен ли модуль Инфоблоков Битрикс.
  2. $this->getResult() - подготавливаем массив $arResult. Это основной блок кода.
  3. $this->includeComponentTemplate() - эта конструкция подключает шаблон.
И по аналогии с типовыми компонентами я обернул весь код в попытку.
Привожу весь код файла class.php:
<?php
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\SystemException;
use Bitrix\Main\Loader;
use Bitrix\Main\Type\Date;

if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

class CIblocList extends CBitrixComponent
{
protected $errors = array();

public function onIncludeComponentLang()
{
Loc::loadMessages(__FILE__);
}

public function onPrepareComponentParams($arParams)
{
if(!isset($arParams["CACHE_TIME"]))
$arParams["CACHE_TIME"] = 36000000;

$arParams["IBLOCK_ID"] = trim($arParams["IBLOCK_ID"]);

if(!preg_match('/^(asc|desc|nulls)(,asc|,desc|,nulls){0,1}$/i', $arParams["SORT_ORDER1"]))
$arParams["SORT_ORDER1"]="DESC";

if(!is_array($arParams["FIELD_CODE"]))
$arParams["FIELD_CODE"] = array();
foreach($arParams["FIELD_CODE"] as $key=>$val)
if(!$val)
unset($arParams["FIELD_CODE"][$key]);

if(!is_array($arParams["PROPERTY_CODE"]))
$arParams["PROPERTY_CODE"] = array();
foreach($arParams["PROPERTY_CODE"] as $key=>$val)
if($val==="")
unset($arParams["PROPERTY_CODE"][$key]);

$arParams["DETAIL_URL"]=trim($arParams["DETAIL_URL"]);

$arParams["TOP_COUNT"] = intval($arParams["TOP_COUNT"]);

$arParams["ACTIVE_DATE_FORMAT"] = trim($arParams["ACTIVE_DATE_FORMAT"]);
if(strlen($arParams["ACTIVE_DATE_FORMAT"])<=0)
$arParams["ACTIVE_DATE_FORMAT"] = Date::convertFormatToPhp(CSite::GetDateFormat("SHORT"));

return $arParams;
}

public function executeComponent()
{
try
{
$this->checkModules();
$this->getResult();
$this->includeComponentTemplate();
}
catch (SystemException $e)
{
ShowError($e->getMessage());
}
}

protected function checkModules()
{
if (!Loader::includeModule('iblock'))
throw new SystemException(Loc::getMessage('CPS_MODULE_NOT_INSTALLED', array('#NAME#' => 'iblock')));
}

protected function prepareDate(&$arItem) {
$DateFormat = $this->arParams["ACTIVE_DATE_FORMAT"];

if (strlen($arItem["DATE_ACTIVE_FROM"]) > 0)
$arItem["DATE_ACTIVE_FROM"] = CIBlockFormatProperties::DateFormat($DateFormat, MakeTimeStamp($arItem["DATE_ACTIVE_FROM"], CSite::GetDateFormat()));
else
$arItem["DATE_ACTIVE_FROM"] = "";
if (strlen($arItem["DATE_CREATE"]) > 0)
$arItem["DATE_CREATE"] = CIBlockFormatProperties::DateFormat($DateFormat, MakeTimeStamp($arItem["DATE_CREATE"], CSite::GetDateFormat()));
else
$arItem["DATE_CREATE"] = "";
if (strlen($arItem["ACTIVE_FROM"]) > 0)
$arItem["ACTIVE_FROM"] = CIBlockFormatProperties::DateFormat($DateFormat, MakeTimeStamp($arItem["ACTIVE_FROM"], CSite::GetDateFormat()));
else
$arItem["ACTIVE_FROM"] = "";
if (strlen($arItem["SHOW_COUNTER_START"]) > 0)
$arItem["SHOW_COUNTER_START"] = CIBlockFormatProperties::DateFormat($DateFormat, MakeTimeStamp($arItem["SHOW_COUNTER_START"], CSite::GetDateFormat()));
else
$arItem["SHOW_COUNTER_START"] = "";
if (strlen($arItem["TIMESTAMP_X"]) > 0)
$arItem["TIMESTAMP_X"] = CIBlockFormatProperties::DateFormat($DateFormat, MakeTimeStamp($arItem["TIMESTAMP_X"], CSite::GetDateFormat()));
else
$arItem["TIMESTAMP_X"] = "";
}

protected function getResult()
{
if ($this->errors)
throw new SystemException(current($this->errors));

$arParams = $this->arParams;

$additionalCacheID = false;
if ($this->startResultCache($arParams['CACHE_TIME'], $additionalCacheID)) {
/SELECT
$arSelect = array_merge($arParams["FIELD_CODE"], array(
"IBLOCK_ID",
"ID",
));
if ($arParams['GET_EXTERNAL_ID'] == 'Y') {
$arSelect[] = 'EXTERNAL_ID';
}
if ($arParams['GET_IBLOCK_SECTION_ID'] == 'Y') {
$arSelect[] = 'IBLOCK_SECTION_ID';
}
foreach ($arParams["PROPERTY_CODE"] as $prop_name) {
$arSelect[] = "PROPERTY_" . $prop_name;
}

/WHERE
$arFilter = array(
"IBLOCK_ID" => $arParams["IBLOCK_ID"],
"IBLOCK_LID" => SITE_ID,
"ACTIVE" => "Y",
);

/ORDER BY
$arSort = array(
$arParams["SORT_BY1"] => $arParams["SORT_ORDER1"]
);
if (!array_key_exists("ID", $arSort))
$arSort["ID"] = "DESC";

$arNavParams["nTopCount"] = $arParams['TOP_COUNT'];

/GETLIST
$rsElement = CIBlockElement::GetList($arSort, $arFilter, false, $arNavParams, $arSelect);
if (!$rsElement) {
$this->abortResultCache();
}

$rsElement->SetUrlTemplates($arParams["DETAIL_URL"], "", $arParams["IBLOCK_URL"]);
while ($obElement = $rsElement->GetNextElement()) {
$arItem = $obElement->GetFields();

$this->prepareDate($arItem);

$arResult["ITEMS"][] = $arItem;
}

$this->arResult = $arResult;

}
}
}

Посмотрите, если свернуть код в редакторе насколько он стал проще для восприятия и организованней. ООП действительно рулит. 

Код компанента Битрикс на классах

Это уже не огромная простыня кода, где ещё надо самостоятельно делить на блоки код чтобы начать что-то понимать. Все вполне наглядно и помещается в один экран.

Скачать полностью архив с компонентом можно отсюда.

От автора:
Мне такой подход понравился. Код, как я уже написал, стал организованней и понятнее. Можно сразу свернуть вспомогательные функции и оставить только главное. Дальше я буду пользоваться только компонентами Битрикс с использованием классов. До встречи!


Комментарии

Подписаться на комментарии
Защита от автоматических сообщений
CAPTCHA
Введите слово на картинке
04


Возврат к списку