Обучаю битриксу программистов, интеграторов. Подробнee ⇒

Компоненты. Старое ядро и новое. BX.ajax.runComponentAction



Документация Битрикс
структура файлов
пример

/local/components/nikaverro/mycomponent/
---class.php
---ajax.php - может быть
---.description.php
---.parameters.php
---/lang/ - ланги
---templates/.default/ - папка с шаблоном
------personal.php
------second.php
------template.php



Пример
.description.php
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
$arComponentDescription = array(
   "NAME" => GetMessage("COMPONENT_NAME"),
   "DESCRIPTION" => GetMessage("COMPONENT_DESCRIPTION"),
   "COMPLEX" => "N",
   "PATH" => array(
      "ID" => GetMessage("COMPONENT_PATH"),
   ),
   "ICON" => "/images/icon.gif",
);
.parameters.php
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
if(!CModule::IncludeModule("iblock") || !CModule::IncludeModule("catalog"))
   return;

$arIBlockType = CIBlockParameters::GetIBlockTypes();
$arIBlock=array();
$rsIBlock = CIBlock::GetList(Array("sort" => "asc"), Array("TYPE" => $arCurrentValues["IBLOCK_TYPE"], "ACTIVE"=>"Y"));
while($arr=$rsIBlock->Fetch()){
   $arIBlock[$arr["ID"]] = "[".$arr["ID"]."] ".$arr["NAME"];
}

$dbProductDiscounts = CCatalogDiscount::GetList(
    array("SORT" => "ASC"),
    array(),
    false,
    false,
    array("ID", "NAME")
    );
while ($arr = $dbProductDiscounts->Fetch()){
    $arDiscountID[$arr['ID']] = "[".$arr["ID"]."] ".$arr["NAME"];  
}
$dbPriceType = CCatalogGroup::GetList(
        array("SORT" => "ASC"),
        array()
    );
while ($arPriceType = $dbPriceType->Fetch()){
    $arPriceCode[$arPriceType["NAME"]] = $arPriceType["NAME"];
}


$arComponentParameters = array(
   "GROUPS" => array(),
   "PARAMETERS" => array(
      "IBLOCK_TYPE" => array(
         "PARENT" => "BASE",
         "NAME" => GetMessage("IBLOCK_TYPE"),
         "TYPE" => "LIST",
         "VALUES" => $arIBlockType,
         "REFRESH" => "Y",
      ),
      "IBLOCK_ID" => array(
         "PARENT" => "BASE",
         "NAME" => GetMessage("IBLOCK_ID"),
         "TYPE" => "LIST",
         "VALUES" => $arIBlock,
         "REFRESH" => "N",
      ),
      "DISCOUNT_ID" => array(
         "PARENT" => "BASE",
         "NAME" => GetMessage("DISCOUNTS"),
         "MULTIPLE" => "Y",
         "TYPE" => "LIST",
         "VALUES" => $arDiscountID,
         "REFRESH" => "N",
      ),
      "FILTER_NAME" => array(
         "PARENT" => "BASE",
         "NAME" => GetMessage("FILTER_NAME"),
         "REFRESH" => "N",
         "DEFAULT" => "arrFilter",
      ),
      "PRICE_CODE" => array(
         "PARENT" => "BASE",
         "NAME" => GetMessage("PRICE_CODE"),
         "MULTIPLE" => "Y",
         "TYPE" => "LIST",
         "VALUES" => $arPriceCode,
         "REFRESH" => "N"
      ),      
      "CACHE_TIME" => array("DEFAULT"=>3600)
   ),
);
component.php
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
//@var array $arParams
//@var array $arResult 

$arParams["FILTER_NAME"] = trim($arParams["FILTER_NAME"]);
if ($arParams["FILTER_NAME"] === '' || !preg_match("/^[A-Za-z_][A-Za-z01-9_]*$/", $arParams["FILTER_NAME"])){
    $arParams["FILTER_NAME"] = "arrFilter";
}
global ${$arParams['FILTER_NAME']};
$arrFilter = &${$arParams['FILTER_NAME']};

if ($this->StartResultCache()){
    
    if(!CModule::IncludeModule("catalog")) {
       $this->AbortResultCache();
       ShowError("CATALOG_MODULE_NOT_INSTALLED");
       return false;
    }

    if(!CModule::IncludeModule("iblock")) {
       $this->AbortResultCache();
       ShowError("IBLOCK_MODULE_NOT_INSTALLED");
       return false;
    }
   
  ///наша логика, наполняем $arResult
  $arResult['DISCOUNT_FILTER'] = $arrFilter;
    $this -> EndResultCache();    
}
else{
    $arrFilter =  $arResult['DISCOUNT_FILTER'];     
}
$this->IncludeComponentTemplate();
 

Как отличить быстро старый компонент от нового:
  • component.php - старый
  • class.php - новый
Переменные, доступные в компоненте - документация Битрикс

раньше была проблема. что в component_epilog.php НЕТ arResult, arParams, мучались с templateData. теперь они доступны.
пути
<?=$component->GetPath()?>/component.php
<?=$this->GetFolder()?>/ajax.php //обращение из template.php к файлу ajax.php в папке шаблона


CBitrixComponent
код классов:
CBitrixComponent
CBitrixComponentTemplate  
простой вариант своего компонента
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
class CTest extends CBitrixComponent{
   
   public function onPrepareComponentParams($arParams){ //переопределяем проверку-подготовку параметров

      $result = array(
         "CACHE_TYPE" => $arParams["CACHE_TYPE"],
         "CACHE_TIME" => isset($arParams["CACHE_TIME"]) ?$arParams["CACHE_TIME"]: 36000000,
         "X" => intval($arParams["X"]),
      );
      return $result;
   }

        public function executeComponent(){ //переопределяем выполнение компонента
      if($this->startResultCache()){
             $this->arResult["Y"] = $this->sqr($this->arParams["X"]);
             $this->includeComponentTemplate(); 
           }
           return $this->arResult["Y"];
   }

   public function sqr($x){ //наш метод
      return $x * $x;
   }
}
чуть посложнее
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Engine\ActionFilter\Csrf;
use Bitrix\Main\Engine\ActionFilter\HttpMethod;
use \Bitrix\Main\Application;

class CTest extends CBitrixComponent implements Controllerable{

   public function configureActions()
    {
        return [ //один ВРОДЕ для всех action
            'calcSqrt' => [  
                'prefilters' => [
                    new HttpMethod(
                        array(HttpMethod::METHOD_POST)
                    ),
                    new Csrf(),
                ],
                'postfilters' => []
            ],
        ];
    }
   
   public function onPrepareComponentParams($arParams){ //переопределяем проверку-подготовку параметров
      global $USER;
      $result = array(
         "CACHE_TYPE" => $arParams["CACHE_TYPE"],
         "CACHE_TIME" => isset($arParams["CACHE_TIME"]) ?$arParams["CACHE_TIME"]: 36000000,
         "X" => intval($arParams["X"]),
         "IS_ADMIN" => $USER->IsAdmin()? "Y" : "N" //кеш будет разный для админов и неадминов
      );
      return $result;
   }

   public function executeComponent(){ //переопределяем выполнение компонента
      if($this->startResultCache()){         
            $this->arResult["Y"] = $this->sqr($this->arParams["X"]); 
            $myTemplate = ($this->arParams["IS_ADMIN"]=="Y")? "testtemplate" : "";            
            $this->includeComponentTemplate($myTemplate); //если не админ, то запустится template.php, если админ, то запустится testtemplate.php
      }

      
      return $this->arResult["Y"];
   }

   public function sqr($x){ //наш метод
      return $x * $x;
   }
   
   public function calcSqrtAction($number,$sessid){ //для контроллера
      if (!check_bitrix_sessid()) {
         throw new \Exception("SESSION_EXPIRED", 1);
      }
      return $this->sqr($number);
   } 
}
template.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
//вывод того, что посчитали executeComponent
?>
<?=$arParams["X"]?>*<?=$arParams["X"]?> = <?=$arResult["Y"]?><br>
<pre>
   <?
   print_r($arParams);
   print_r($arResult);
   ?>
</pre>

//а это предлагаем рассчитать тут же для любого числа
<input type="text" id="number"><button id="calc">рассчитать квадрат</button>
<br>
<div id="result"></div>
<script>
   $(document).ready(function() {
        $(document).on('click', '#calc', function(e) {
            e.preventDefault();
            if($('#number').val()===""){
               $('#result').html("не заполнено поле");
            }
            else if($('#number').val()*1 != $('#number').val()){
                $('#result').html("введено НЕ число");
            }    
            else{

                //по фиг на порядок, главное назвать также как и описано в calcSqrtAction($number, $sessid) 
                var data = {                    
                    sessid: BX.message('bitrix_sessid'),
                    number: $('#number').val(),
                };
                var request = BX.ajax.runComponentAction("test:mycomponent", "calcSqrt", {
                    mode: "class",
                    data: data 
                });
                
                //ловим ошибки
                request.catch(function(response) {                                                                 
                    console.log(response);                              
                    
                });

                //получаем ответ
                request.then(function(response) {                                
                    console.log(response);
                    if (response.status == "success") {
                        $('#result').html(response.data);                                                           
                    }
                });
            }
        });
    });
</script>
Запуск компонента
$APPLICATION->IncludeComponent("test:mycomponent","",[
   "X"=>3,   
]);

CBitrixComponent запускает
  1. onPrepareComponentParams
  2. executeComponent
в executeComponent, можно включить $this->includeComponentTemplate($myTemplate), но не обязательно, компонент может и без шаблона отработать

includeComponentTemplate подключит    
  1. $this->__template класса CBitrixComponentTemplate    который подключит result_modifier.php,  template.php (или другой файл. который указан)  - кешируются
  2. component_epilog.php - исполняется на каждом хите

пусть компонент запущен с шаблоном mytemplate, тогда
$this->IncludeComponentTemplate($s); 

$s - пустая строка
запустится /templates/mytemplate/template.php

$s - непустая строка. Например, 'list'
запустится /templates/mytemplate/list.php
Если блог был полезным, можете угостить меня "чашечкой кофе" :)

Сбер по номеру телефона +7 (953) 585-13-09 Вероника.
Спасибо!