44 Live Templates для Битрикса

Кому

Данная статья носит справочный характер и будет интересна лишь программистам CMS 1С-Битрикс, причем тому сегменту, который использует в разработке чудесную IDE PhpStorm. Такая комбинация встречается нередко, в нашей компании практически все программисты пользуются именно ей.

О чем

В данной IDE используется механизм расширяемых Live templates’ов. Эти template’ы (будем далее по тексту называть их LT) представляют собой заранее заданные последовательности символов, которые по нажатию на клавишу Tab можно развернуть в “заготовки” кода. Не сказать, что JetBrains первые изобрели этот механизм, но они уж точно знают, как сделать его удобными. Собственно, своими наработками для CMS 1С-Битрикс я и хотел поделиться. Live templates

Главный модуль

По старой программистской традиции, начнем с функции модуля main. Модуль растет с каждым обновлением, обилие его фич уже не упомнить - что уж говорить о названиях методов. Вот, например методы для регистрации CSS и JS ( SetAdditionalCSS и AddHeadScript соответственно). Никогда не мог понять и запомнить - почему стили надо “Установить дополнительными” а скрипты “добавить в head” (дословный перевод названий методов). Но, спасибо PhpStorm, это больше не проблема. Мои первые два LT:

addcss

$APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH . $END$ );

addjs

$APPLICATION->AddHeadScript(SITE_TEMPLATE_PATH . $END$ );

Последовательность $END$ определяет место, в котором окажется курсор после “применения” LT, то есть можно будет сразу написать путь к файлу относительно шаблона сайта.

Частенько требуется понять в шаблоне сайта, на какой же мы странице сайта (чтобы, например, не выводить новости в левом меню на основной странице новостей или скрывать хлебные крошки на главной странице). Для этого подойдут следующие два LT:

isindex

$isIndex = $APPLICATION->GetCurPage(false) == SITE_DIR;

(проверка на главную страницу)

ispage

strpos($APPLICATION->GetCurUri(), '/ $END$ /') !== false;

(проверка на наличие /<название_раздела>/ в адресе)

А как часто вы подключаете модули в агентах или обработчиках? По-хорошему - должны постоянно. Лидером по использованию, безусловно, является модуль Информационных блоков - поэтому для него я и создал еще один LT.

ibl

CModule::IncludeModule("iblock")

Для работы с логами отлично себя зарекомендовали такие варианты:

m2l

AddMessage2Log( $END$ );

m2lpr

AddMessage2Log(print_r( $END$ , TRUE));

Инфоблоки

Вот уж где LT нужны на каждом шаге. Вспомните только, сколько GetList’ов приходится делать! А самый известный из них, любимец публики, закладка в браузере на который есть у каждого уважающего себя битриксоида - CIBlockElement::GetList . Как же с ним бороться? А вот так:

egl

$arOrder = array("SORT" => "ASC");
$arFilter = array( $END$ );
$arSelectFields = array("ID","ACTIVE", "NAME");
$rsElements = CIBlockElement::GetList($arOrder, $arFilter, FALSE, FALSE, $arSelectFields);
while($arElement = $rsElements->GetNext())
{
}

Стоило перейти к инфоблокам, LT перестали быть однострочными. Но, зато сразу есть все что нужно - и массив для сортировки, и фильтр (курсор после разворачивания переместится именно туда), и поле для ограничения извлекаемых столбцов. Мне в 95% случаев хватает. Часто выручает такой вот LT, кстати, как раз для фильтра:

filter

"ACTIVE" => "Y", "SECTION_GLOBAL_ACTIVE" => "Y", "ACTIVE_DATE" => "Y"

А как же можно забыть про “старшего брата” - CIBlockSection::GetList ?

sgl

$arSort = array("SORT" => "ASC");
$arFilter = array("IBLOCK_ID" => $arParams["IBLOCK_ID"], "ID" => $END$ );
$rsSections = CIBlockSection::GetList($arSort, $arFilter);
while ($arSection = $rsSections->GetNext())
{
   
}

Как видите, я настроил LT таким образом, чтобы сразу фильтровать разделы по ID - именно такие запросы мне нужны чаще всего.

Компоненты

Я решил описать LT для компонентов после главного модуля, потому что так логичнее. Сначала мы данные выбираем, а затем уже подготавливаем и выводим. Наверняка, каждому взрослому программисту Битрикса известна конструкция для такого LT:

res

$arImg = CFile::ResizeImageGet( $END$ , array('width' => 150, 'height' => 85));

Это самая первая и безобидная версия LT. Магические числа, никаких проверок - все как в детстве. Сейчас она выросла до такого вот монстра.

res2

if (isset($arParams["RESIZE_TYPE"]) && $arParams["RESIZE_TYPE"] != -1 && $arParams["WIDTH"] && $arParams["HEIGHT"])
{
    foreach ($arResult["ITEMS"] as &$arItem)
    {
        if ($arItem["PREVIEW_PICTURE"])
        {
            $arImg = CFile::ResizeImageGet($arItem["PREVIEW_PICTURE"], array("width" => $arParams["WIDTH"], "height" =>$arParams["HEIGHT"]), intval($arParams["RESIZE_TYPE"]), true);
            if ($arImg)
            {
                $arItem["PREVIEW_PICTURE"]["SRC"] = $arImg["src"];
                $arItem["PREVIEW_PICTURE"]["WIDTH"] = $arImg["width"];
                $arItem["PREVIEW_PICTURE"]["HEIGHT"] = $arImg["height"];
            }
        }
    }
}

А кто помнит наизусть архинеудобный метод, чтобы добавить в кеш компонента новую переменную? Черт с ним, с именем ( SetResultCacheKeys , кстати), надо же еще упомнить, для какого объекта его вызывать. А у нас используют LT:

cache

$this->__component->SetResultCacheKeys(array(" $END$ "));

И сразу все понятно, без мороки.

А теперь, наверное, стоит рассказать и о шаблонах компонентов. Знаете ли вы, что шаблон, например, списка новостей, можно сотворить за 1 секунду? Да еще и с поддержкой Эрмитажа и постраничкой! Это делают так:

items

<?if ($arResult["ITEMS"]): ?>
    <?if($arParams["DISPLAY_TOP_PAGER"]):?>
        <?=$arResult["NAV_STRING"]?>
    <?endif?>
    <?foreach ($arResult["ITEMS"] as $i => $arItem): ?>
        <?
            $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
            $this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
            $id = $this->GetEditAreaId($arItem['ID']);
        ?>
        <div id="<?=$id?>">
             $END$
        </div>
    <? endforeach?>
    <?if($arParams["DISPLAY_BOTTOM_PAGER"]):?>
        <?=$arResult["NAV_STRING"]?>
    <?endif?>
<? endif ?>

Если шаблон уже готов и нужен только эрмитаж, то на помощь спешит getid:

getid

<?
    $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
    $this->AddDeleteAction($arItem['ID'],$arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" =>GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
    $id = $this->GetEditAreaId($arItem['ID']);
?>

Надеюсь, мне удалось донести до консервативных от природы коллег-программистов пользу LT в PhpStorm. А теперь,в component_epilog’е, так сказать, все мои LT даром, в двух таблицах. В первой - моя таблица “аббревиатур” для популярных переменных, а “взрослые” LT во второй.

Аббревиатуры

Live template Расшифровка
app $APPLICATION
arbi $arBasketItem
are $arElement
arf $arField
arr $arResult
curr CURRENCY
detpic DETAIL_PICTURE
dett DETAIL_TEXT
disp DISPLAY_PROPERTIES
disv DISPLAY_VALUE
dpu DETAIL_PAGE_URL
prepic PREVIEW_PICTURE
pret PREVIEW_TEXT
prop PROPERTIES
spu SECTION_PAGE_URL
stp SITE_TEMPLATE_PATH

Основные LT

addcss Добавить CSS файл для вывода в head’е страницы
$APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH . $END$ );
addjs Добавить JS файл для вывода в head’е страницы
$APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH . $END$ );
ajax Минимальный необходимый код для работы ajax-страниц (без шаблона сайта)
<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$END$
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
?>
ajax Минимальный необходимый код для работы ajax-страниц (без шаблона сайта)
<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$END$
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
?>
artp Создать небольшой массив параметров шаблона компонента (как пример)
$arTemplateParameters =array(
    "DISPLAY_DATE" => Array(
        "NAME" =>"Display date,
        "TYPE" => "CHECKBOX",
        "DEFAULT" => "Y",
    ),
    "DISPLAY_NAME" => Array(
        "NAME" => "Display name",
        "TYPE" => "CHECKBOX",
        "DEFAULT" => "Y",
    ),
    "DISPLAY_PICTURE" => Array(
        "NAME" => "Display picture",
        "TYPE" =>"CHECKBOX",
        "DEFAULT" => "Y",
    ),
    "DISPLAY_PREVIEW_TEXT"=> Array(
        "NAME" => "Display preview text",
        "TYPE" => "CHECKBOX",
        "DEFAULT" => "Y",
    ),
);
cache Добавить ключ $arResult в кеш компонента (“пробросить” в component_epilog.php)/td>
$this->__component->SetResultCacheKeys(array(" $END$ "));
dirs Разбить URL по сегментам
// текущий раздел строкой
$curDir = $APPLICATION->GetCurDir();
// текущий раздел массивом
$arDirs = array_diff(explode("/", $curDir), Array(""));
egl Получить элементы инфоблока
$arOrder = array("SORT" => "ASC");
$arFilter = array( $END$ );
$arSelectFields = array("ID", "ACTIVE", "NAME");
$rsElements = CIBlockElement::GetList($arOrder, $arFilter, FALSE, FALSE, $arSelectFields);
while($arElement = $rsElements->GetNext())
{
}
filter Самый популярный фильтр для элементов инфоблоков
"ACTIVE" => "Y", "SECTION_GLOBAL_ACTIVE" => "Y", "ACTIVE_DATE" => "Y"
foreari Пройтись циклом по элементам в компоненте
foreach ($arResult["ITEMS"] as $i => $arItem)
{
    $END$
   $arResult["ITEMS"][$i] = $arItem;
}
getid Получить id элемента для Эрмитажа
<?
   $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
   $this->AddDeleteAction($arItem['ID'],$arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" =>GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
   $id = $this->GetEditAreaId($arItem['ID']);
?>
getsid Получить id раздела для Эрмитажа
<?
   $this->AddEditAction($arSection['ID'], $arSection['EDIT_LINK'], CIBlock::GetArrayByID($arSection["IBLOCK_ID"], "SECTION_EDIT"));
   $this->AddDeleteAction($arSection['ID'], $arSection['DELETE_LINK'], CIBlock::GetArrayByID($arSection["IBLOCK_ID"], "SECTION_DELETE"), array("CONFIRM" => GetMessage('CT_BCSL_ELEMENT_DELETE_CONFIRM')));
   $id = $this->GetEditAreaId($arSection['ID']);
?>
ibl Подключить модуль инфоблоков
CModule::IncludeModule("iblock")
igl Получить инфоблоки
$arOrder = array("SORT" => "ASC");
$arFilter = array( $END$ );
$rsIBlocks = CIBlock::GetList($arOrder, $arFilter);
while ($arIBlock = $rsIBlocks->GetNext())
{
}
inc Вывод включаемой области
<?$APPLICATION->IncludeFile(
    SITE_DIR."include/ $END$ .php",
    Array(),
    Array("MODE"=>"text")
);?>
isindex Проверка на главную страницу
$isIndex = $APPLICATION->GetCurPage(false) == SITE_DIR;
ispage Проверка на внутреннюю страницу
strpos($APPLICATION->GetCurUri(), '/ $END$ /') !== false;
items Вывод элементов
<?if ($arResult["ITEMS"]): ?>
    <?if($arParams["DISPLAY_TOP_PAGER"]):?>
        <?=$arResult["NAV_STRING"]?>
    <?endif?>
    <?foreach ($arResult["ITEMS"] as $i => $arItem): ?>
        <?
            $this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
            $this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
            $id = $this->GetEditAreaId($arItem['ID']);
        ?>
        <div id="<?=$id?>">
             $END$
        </div>
    <? endforeach?>
    <?if($arParams["DISPLAY_BOTTOM_PAGER"]):?>
        <?=$arResult["NAV_STRING"]?>
    <?endif?>
<? endif ?>
log Объявить переменную для лога
define("LOG_FILENAME", $_SERVER["DOCUMENT_ROOT"]."/log42.txt");
m2l Вывести выражение в лог (для примитивных типов)
AddMessage2Log( $END$ );
m2lpr Вывести выражение в лог (для массивов и объектов)
AddMessage2Log(print_r( $END$ , TRUE));
pgl Получить свойства инфоблока
$arSort = array("SORT" => "ASC");
$arFilter = array( $END$ );
$rsProperties = CIBlockProperty::GetList($arSort, $arFilter);
while ($arProperty = $rsProperties->GetNext())
{
}
res Сжать изображение
$arImg = CFile::ResizeImageGet( $END$ , array('width' => 150, 'height' => 85));
res2 Сжать анонсные изображения элементов, настройки сжатия взять из параметров
if (isset($arParams["RESIZE_TYPE"]) && $arParams["RESIZE_TYPE"] != -1 && $arParams["WIDTH"] && $arParams["HEIGHT"])
{
    foreach ($arResult["ITEMS"] as &$arItem)
    {
        if ($arItem["PREVIEW_PICTURE"])
        {
            $arImg = CFile::ResizeImageGet($arItem["PREVIEW_PICTURE"], array("width" => $arParams["WIDTH"], "height" =>$arParams["HEIGHT"]), intval($arParams["RESIZE_TYPE"]), true);
            if ($arImg)
            {
                $arItem["PREVIEW_PICTURE"]["SRC"] = $arImg["src"];
                $arItem["PREVIEW_PICTURE"]["WIDTH"] = $arImg["width"];
                $arItem["PREVIEW_PICTURE"]["HEIGHT"] = $arImg["height"];
            }
        }
    }
}
resitmpre Сжать анонсные изображения элементов
foreach ($arResult["ITEMS"] as $i => $arItem)
{
    if ($arItem["PREVIEW_PICTURE"])
    {
        $arImg = CFile::ResizeImageGet($arItem["PREVIEW_PICTURE"]["ID"], array('width' => $WIDTH$, 'height' =>$HEIGHT$));
        $arResult["ITEMS"][$i]["PREVIEW_PICTURE"]["SMALL_SRC"] = $arImg["src"];
    }
}
sections Вывести разделы в компоненте
<?if ($arResult["SECTIONS"]): ?>
    <?foreach ($arResult["SECTIONS"] as $i =>$arSection): ?>
        <?
            $this->AddEditAction($arSection['ID'], $arSection['EDIT_LINK'], CIBlock::GetArrayByID($arSection["IBLOCK_ID"],"SECTION_EDIT"));
            $this->AddDeleteAction($arSection['ID'],$arSection['DELETE_LINK'], CIBlock::GetArrayByID($arSection["IBLOCK_ID"], "SECTION_DELETE"), array("CONFIRM" => GetMessage('CT_BCSL_ELEMENT_DELETE_CONFIRM')));
            $id = $this->GetEditAreaId($arSection['ID']);
        ?>
        <div id="<?=$id?>">
        </div>
    <? endforeach?>
<? endif ?>
sgl Получить разделы инфоблока
$arSort = array("SORT" => "ASC");
$arFilter = array("IBLOCK_ID" => $arParams["IBLOCK_ID"], "ID" => $arFirstLevelSectionsIDs);
$rsSections = CIBlockSection::GetList($arSort,$arFilter);
while ($arSection = $rsSections->GetNext())
{
}
ugl Получить пользователей
$arFilter = array("ID" => $USER->GetID());
$arParam = array("SELECT" => array("UF_SPHERE"), "FIELDS" => array("ID"));
$rsUsers = CUser::GetList(($by="ID"), ($order="ASC"), $arFilter, $arParam);
while($arUser = $rsUsers->GetNext())
{
    echo '<pre>', print_r($arUser, true),'</pre>';
}

UPD:

Если вас заинтересовали Live Templates для Битрикса, оставьте в комментариях свой e-mail и мы поделимся файлом экспорта =)

UPD2:

Ссылка для скачивания файлика бесплатно без смс =)

Комментарии (39)

...
  • Зацепин Евгений
  • 02.06.2014 10:47:43
Спасибо за подборку. Некоторое время назад начал создавать свою, но об автоматизации некоторых действий почему-то мысли в голову не приходили =)
Был бы благодарен, если бы вы выложили экспорт этих LiveTemplates в виде файла.
...
  • Сергей
  • 02.06.2014 20:10:39
Отличная статья. Для меня амый используемый LT это pre

echo "<pre>";
print_r ($end$);
echo "<pre>";
...
  • Зацепин Евгений
  • 02.06.2014 20:18:01
Я бы порекомендовал отказываться от print_r в сторону phpconsole или хотя бы dump-r (оба ищутся в composer). На порядок удобнее, а сообщения phpconsole не увидят пользователи при любом раскладе.
...
  • Максим
  • 02.06.2014 20:12:06
Спасибо за статью, сам правда пользуюсь phpDesigner 8. Там есть что то похожее, только вызывается Ctrl + J. Взял себе на заметку пару ваших LT. Как вариант я еще использую вызов компонентов. Например для вызова списка новостей указываю bnewslist.
...
  • Игорь
  • 02.06.2014 20:57:53
Вот это полезность! Буду очень благодарен, если поделитесь экспортом
...
  • Дмитрий
  • 02.06.2014 21:00:46
Спасибо за проделанный труд! Скинь пожалуйста файл.
...
  • Petr Grishin
  • 02.06.2014 21:07:59
Тихий ужас..
...
  • Vitalii
  • 02.06.2014 23:25:56
Спасибо, скиньте и мне пожалуйста файл
...
  • Виталий
  • 03.06.2014 00:54:21
Хорошая подборка самых необходимых API-шаблонов и отличная статья. Буду очень благодарен, если поделитесь файлом экспорта. Сам так же пользуюсь шаблонами вставки вызовов компонентов. Спасибо за труд!
...
  • Александр
  • 03.06.2014 06:00:18
Буду благодарен за файлик.
...
  • Максим
  • 03.06.2014 10:38:54
Буду благодарен за файлик.
...
  • Роман
  • 03.06.2014 11:44:29
Спасибо за подборку. Буду рад воспользоваться.
...
  • Сергей
  • 03.06.2014 16:14:41
Хорошая подборка.
Если не затруднит и мне поделитесь
...
Друзья, спасибо за проявленный интерес к статье.
Все, кто на 16:20 3 июня оставил свои адреса, должны получить файл.
Как наберется еще несколько адресов, снова отправим.
Спасибо!
http://shot.qip.ru/00lGyK-61appUNcVm/
...
  • peektoseen
  • 03.06.2014 21:43:12
Тоже хочу. Вышлите пожалуйста файлик.
...
  • Александр
  • 04.06.2014 07:51:28
И мне тоже вышлите пожалуйста
...
  • Алексей
  • 04.06.2014 11:01:14
Буду благодарен за файл
...
  • Максим
  • 05.06.2014 14:52:55
Интереснейшая статья.
Буду благодарен за файл
...
  • Юлия
  • 06.06.2014 09:38:11
Очень здорово! Можно файл, пожалуйста?
...
Друзья, спасибо за проявленный интерес к статье.
Все, кто на 10:20 7 июня оставил свои адреса, должны получить файл.
...
  • Александр
  • 10.06.2014 21:25:09
И мне тоже вышлите пожалуйста))
...
  • Сергей
  • 21.06.2014 12:24:21
Спасибо за статью.
Есть еще очень интересная переменная $SELECTION$ в LiveTemplates'ах, было бы полезно и ее осветить в виде апдейта к статье.

Делюсь своими наработками.
https://github.com/matiaspub/bxCompSnpt
...
  • Дмитрий
  • 14.07.2014 14:37:53
Вышлите пожалуйста и мне экспорт.

Спасибо!
...
Друзья, спасибо за проявленный интерес к статье.
Все, кто на 14:00 15 июля оставил свои адреса, должны получить файл.
...
  • Talant
  • 04.09.2014 10:21:55
День добрый, Александр, спасибо за статью и такую подборку! Скиньте пожалуйста и мне файлик.
...
  • Максим
  • 13.09.2014 13:06:04
Интереснейшая статья.
Буду благодарен за файл!
...
  • Иван
  • 20.11.2014 09:44:48
Добрый день!
Скиньте пожалуйста файл.
...
  • Колян
  • 16.01.2015 17:24:59
ОГОНЬ тема) достало писать с нуля каждый раз) киньте мне это добро)
А как юзать все это? немного не понял, краткий туториал по клавишам можно?
СПАСИБОСЫ) отличная разработка
...
  • Иван Белицкий
  • 29.01.2015 21:36:03
Крутая вещь!

Скиньте пожалуйста файл.
...
  • Юрий Пономарев
  • 05.05.2015 12:09:05
Статья что надо. Буду премного благодарен за файл.
...
  • Михаил Торохов
  • 08.05.2015 11:32:47
Спасибо за интересную статью, хотелось бы получить файлик.
...
  • Дмитрий
  • 12.05.2015 09:45:56
Интересная статья. Вышлите файлик. Спасибо!
...
  • Виталий
  • 27.11.2015 18:49:30
файлик пожалуйста киньте... и когда под D7 будет? и будет ли?
...
  • Vit bitrix-developer
  • 18.02.2016 19:39:29
Файлик, пожалуйста : )
...
  • Алексей Андреевич
  • 23.02.2016 15:11:21
День добрый, Александр, спасибо за статью и такую подборку! Скиньте пожалуйста и мне файлик.
...
Друзья, рассылка продолжается. Не стесняйтесь спрашивать.
...
  • Никита
  • 10.05.2016 16:28:36
Доброго дня. И мне подборку можно?
...
  • Дарья Кливец
  • 20.07.2016 18:25:53
Можно файлик. Плиз
...
  • Михаил Дроздов
  • 19.09.2016 17:19:29
Присоединяюсь, можно файлик?