Битрикс. Создание своего модуля. Часть 1 из 3

24.10.2018

Теги: CMSWeb-разработкаБитриксМодульСобытиеУстановка

Наш модуль после установки добавляет на страницы сайта кнопку плавной прокрутки страницы вверх. Какие файлы и папки могут и должны быть, можно изучить в соответствующем разделе документации Битрикс. Модуль разместим в директории local/modules и создадим такую файловую структуру:

[scrollup]
    [install]
        [assets]
            [scripts]
                script.js
            [styles]
                style.css
        index.php
        step.php
        unstep.php
        version.php
    [lang]
        [ru]
            [install]
                index.php
            options.php
    [lib]
        Main.php
    include.php
    options.php

Как видите, внутри local/modules/scrollup у нас:

  • install — набор скриптов для установки и удаления модуля;
  • lang — набор языковых файлов модуля;
  • lib — набор файлов, в которых реализуется логика решения;
  • include.php — файл, подключаемый при вызове модуля в коде;
  • options.php — страница настроек, подключаемая в административной части.

Рассмотрим подробнее папку install:

  • assets — содержит JavaScript и CSS кнопки, которые будут подключаться в пользовательской части;
  • index.php — файл, в котором содержится описание модуля и реализуется его установка и удаление;
  • step.php и unstep.php — соответственно шаги установки и удаления, их может быть несколько;
  • version.php — файл содержит версию и время обновления нашего модуля.
<?php
/*
 * Файл local/modules/scrollup/install/version.php
 */

$arModuleVersion = array(
    'VERSION'      => '1.0.0',
    'VERSION_DATE' => '2018-10-20 11:00:00'
);

Теперь нам нужно написать класс, в котором будет реализована установка и удаление модуля. Имя класса должно совпадать с директорией модуля и являться наследником от CModule. Метод doInstall() вызывается при установке модуля из панели управления, метод doUninstall() — при деинсталляции модуля. Метод doInstall() подключает файл step.php, а метод doUninstall() — файл unstep.php

<?php
/*
 * Файл local/modules/scrollup/install/index.php
 */

use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ModuleManager;
use Bitrix\Main\Config\Option;
use Bitrix\Main\EventManager;
use Bitrix\Main\Application;
use Bitrix\Main\IO\Directory;

Loc::loadMessages(__FILE__);

class scrollup extends CModule {

    public function __construct() {
        if (is_file(__DIR__.'/version.php')) {
            include_once(__DIR__.'/version.php');
            $this->MODULE_ID           = get_class($this);
            $this->MODULE_VERSION      = $arModuleVersion['VERSION'];
            $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'];
            $this->MODULE_NAME         = Loc::getMessage('SCROLLUP_NAME');
            $this->MODULE_DESCRIPTION  = Loc::getMessage('SCROLLUP_DESCRIPTION');
        } else {
            CAdminMessage::showMessage(
                Loc::getMessage('SCROLLUP_FILE_NOT_FOUND').' version.php'
            );
        }
    }
    
    public function doInstall() {

        global $APPLICATION;

        // мы используем функционал нового ядра D7 — поддерживает ли его система?
        if (CheckVersion(ModuleManager::getVersion('main'), '14.00.00')) {
            // копируем файлы, необходимые для работы модуля
            $this->installFiles();
            // создаем таблицы БД, необходимые для работы модуля
            $this->installDB();
            // регистрируем модуль в системе
            ModuleManager::registerModule($this->MODULE_ID);
            // регистрируем обработчики событий
            $this->installEvents();
        } else {
            CAdminMessage::showMessage(
                Loc::getMessage('SCROLLUP_INSTALL_ERROR')
            );
            return;
        }

        $APPLICATION->includeAdminFile(
            Loc::getMessage('SCROLLUP_INSTALL_TITLE').' «'.Loc::getMessage('SCROLLUP_NAME').'»',
            __DIR__.'/step.php'
        );
    }
    
    public function installFiles() {
        // копируем js-файлы, необходимые для работы модуля
        CopyDirFiles(
            __DIR__.'/assets/scripts',
            Application::getDocumentRoot().'/bitrix/js/'.$this->MODULE_ID.'/',
            true,
            true
        );
        // копируем css-файлы, необходимые для работы модуля
        CopyDirFiles(
            __DIR__.'/assets/styles',
            Application::getDocumentRoot().'/bitrix/css/'.$this->MODULE_ID.'/',
            true,
            true
        );
    }
    
    public function installDB() {
        return;
    }

    public function installEvents() {
        // перед выводом буферизированного контента добавим свой HTML код,
        // в котором сохраним настройки для нашей кнопки прокрутки наверх
        EventManager::getInstance()->registerEventHandler(
            'main',
            'OnBeforeEndBufferContent',
            $this->MODULE_ID,
            'ScrollUp\\Main',
            'appendJavaScriptAndCSS'
        );
    }

    public function doUninstall() {

        global $APPLICATION;

        $this->uninstallFiles();
        $this->uninstallDB();
        $this->uninstallEvents();

        ModuleManager::unRegisterModule($this->MODULE_ID);

        $APPLICATION->includeAdminFile(
            Loc::getMessage('SCROLLUP_UNINSTALL_TITLE').' «'.Loc::getMessage('SCROLLUP_NAME').'»',
            __DIR__.'/unstep.php'
        );

    }

    public function uninstallFiles() {
        // удаляем js-файлы
        Directory::deleteDirectory(
            Application::getDocumentRoot().'/bitrix/js/'.$this->MODULE_ID
        );
        // удаляем css-файлы
        Directory::deleteDirectory(
            Application::getDocumentRoot().'/bitrix/css/'.$this->MODULE_ID
        );
        // удаляем настройки нашего модуля
        Option::delete($this->MODULE_ID);
    }
    
    public function uninstallDB() {
        return;
    }
    
    public function uninstallEvents() {
        // удаляем наш обработчик события
        EventManager::getInstance()->unRegisterEventHandler(
            'main',
            'OnBeforeEndBufferContent',
            $this->MODULE_ID,
            'ScrollUp\\Main',
            'appendJavaScriptAndCSS'
        );
    }

}
<?php
/*
 * Файл local/modules/scrollup/lang/ru/install/index.php
 */

$MESS['SCROLLUP_NAME']              = 'Кнопка «Наверх»';
$MESS['SCROLLUP_DESCRIPTION']       = 'Добавляет на сайт кнопку плавной прокрутки наверх.';

$MESS['SCROLLUP_FILE_NOT_FOUND']    = 'Не найден файл';
$MESS['SCROLLUP_INSTALL_TITLE']     = 'Установка модуля';
$MESS['SCROLLUP_INSTALL_ERROR']     = 'Версия главного модуля ниже 14, обновите систему.';
$MESS['SCROLLUP_INSTALL_SUCCESS']   = 'Модуль успешно установлен';
$MESS['SCROLLUP_INSTALL_FAILED']    = 'Ошибка при установке модуля';

$MESS['SCROLLUP_UNINSTALL_TITLE']   = 'Удаление модуля';
$MESS['SCROLLUP_UNINSTALL_SUCCESS'] = 'Модуль успешно удален';
$MESS['SCROLLUP_UNINSTALL_FAILED']  = 'Ошибка при удалении модуля';

$MESS['SCROLLUP_RETURN_MODULES']    = 'Вернуться в список модулей';
<?php
/*
 * Файл local/modules/scrollup/install/step.php
 */

use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

if (!check_bitrix_sessid()) {
    return;
}

if ($errorException = $APPLICATION->getException()) {
    // ошибка при установке модуля
    CAdminMessage::showMessage(
        Loc::getMessage('SCROLLUP_INSTALL_FAILED').': '.$errorException->GetString()
    );
} else {
    // модуль успешно установлен
    CAdminMessage::showNote(
        Loc::getMessage('SCROLLUP_INSTALL_SUCCESS')
    );
}
?>

<form action="<?= $APPLICATION->getCurPage(); ?>"> <!-- Кнопка возврата к списку модулей -->
    <input type="hidden" name="lang" value="<?= LANGUAGE_ID; ?>" />
    <input type="submit" value="<?= Loc::getMessage('SCROLLUP_RETURN_MODULES'); ?>">
</form>
<?php
/*
 * Файл local/modules/scrollup/install/unstep.php
 */

use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

if (!check_bitrix_sessid()){
    return;
}

if ($errorException = $APPLICATION->getException()) {
    // ошибка при удалении модуля
    CAdminMessage::showMessage(
        Loc::getMessage('SCROLLUP_UNINSTALL_FAILED').': '.$errorException->GetString()
    );
} else {
    // модуль успешно удален
    CAdminMessage:showNote(
        Loc::getMessage('SCROLLUP_UNINSTALL_SUCCESS')
    );
}
?>

<form action="<?= $APPLICATION->getCurPage(); ?>"> <!-- Кнопка возврата к списку модулей -->
    <input type="hidden" name="lang" value="<?= LANGUAGE_ID; ?>" />
    <input type="submit" value="<?= Loc::getMessage('SCROLLUP_RETURN_MODULES'); ?>">
</form>

Теперь в панели управления на странице «Настройки • Настройки продукта • Модули» мы видим наш модуль:

И можем установить его:

Создадим страницу настроек для модуля. Через панель управления контент менеджер сможет:

  • Включать/выключать модуль;
  • Подключать библиотеку jQuery, если она еще не подключена;
  • Изменять ширину/высоту/радиус и цвет кнопки;
  • Менять положение кнопки и скорость анимации.
<?php
/*
 * Файл local/modules/scrollup/options.php
 */

use Bitrix\Main\Localization\Loc;
use Bitrix\Main\HttpApplication;
use Bitrix\Main\Loader;
use Bitrix\Main\Config\Option;

Loc::loadMessages(__FILE__);

// получаем идентификатор модуля
$request = HttpApplication::getInstance()->getContext()->getRequest();
$module_id = htmlspecialchars($request['mid'] != '' ? $request['mid'] : $request['id']);
// подключаем наш модуль
Loader::includeModule($module_id);

/*
 * Параметры модуля со значениями по умолчанию
 */
$aTabs = array(
    array(
        /*
         * Первая вкладка «Основные настройки»
         */
        'DIV'     => 'edit1',
        'TAB'     => Loc::getMessage('SCROLLUP_OPTIONS_TAB_GENERAL'),
        'TITLE'   => Loc::getMessage('SCROLLUP_OPTIONS_TAB_GENERAL'),
        'OPTIONS' => array(
            array(
                'switch_on',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_SWITCH_ON'), // поясняющий текст — «Включить прокрутку»
                'Y',                                           // значение по умолчанию «да»
                array('checkbox')                              // тип элемента формы — checkbox
            ),
            array(
                'jquery_on',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_JQUERY_ON'), // поясняющий текст — «Подключить jQuery»
                'N',                                           // значение по умолчанию «нет»
                array('checkbox')                              // тип элемента формы — checkbox
            ),
        )
    ),
    array(
        /*
         * Вторая вкладка «Дополнительные настройки»
         */
        'DIV'     => 'edit2',
        'TAB'     => Loc::getMessage('SCROLLUP_OPTIONS_TAB_ADDITIONAL'),
        'TITLE'   => Loc::getMessage('SCROLLUP_OPTIONS_TAB_ADDITIONAL'),
        'OPTIONS' => array(
            /*
             * секция «Внешний вид»
             */
            Loc::getMessage('SCROLLUP_OPTIONS_SECTION_VIEW'),
            array(
                'width',                                    // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_WIDTH'),  // поясняющий текст — «Ширина (пикселей)»
                '50',                                       // значение по умолчанию 50px
                array('text', 5)                            // тип элемента формы — input type="text", ширина 5 симв.
            ),
            array(
                'height',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_HEIGHT'), // поясняющий текст — «Высота (пикселей)»
                '50',                                       // значение по умолчанию 50px
                array('text', 5)                            // тип элемента формы — input type="text", ширина 5 симв.
            ),
            array(
                'radius',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_RADIUS'), // поясняющий текст — «Радиус (пикселей)»
                '50',                                       // значение по умолчанию 50px
                array('text', 5)                            // тип элемента формы — input type="text", ширина 5 симв.
            ),
            array(
                'color',                                    // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_COLOR'),  // поясняющий текст — «Цвет фона»
                '#bf3030',                                  // значение по умолчанию #bf3030
                array('text', 5)                            // тип элемента формы — input type="text", ширина 5 симв.
            ),
            /*
             * секция «Положение на странице»
             */
            Loc::getMessage('SCROLLUP_OPTIONS_SECTION_LAYOUT'),
            array(
                'side',                                       // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_POSITION'), // поясняющий текст — «Положение кнопки»
                'left',                                       // значение по умолчанию «left»
                array(
                    'selectbox',                              // тип элемента формы — <select>
                    array(
                        'left'  => Loc::getMessage('SCROLLUP_OPTIONS_SIDE_LEFT'),
                        'right' => Loc::getMessage('SCROLLUP_OPTIONS_SIDE_RIGHT')
                    )
                )
            ),
            array(
                'indent_bottom',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_INDENT_BOTTOM'), // поясняющий текст — «Отступ снизу (пикселей)»
                '10',                                              // значение по умолчанию 10px
                array('text', 5)                                   // тип элемента формы — input type="text"
            ),
            array(
                'indent_side',                                     // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_INDENT_SIDE'),   // поясняющий текст — «Отступ сбоку (пикселей)»
                '10',                                              // значение по умолчанию 10px
                array('text', 5)                                   // тип элемента формы — input type="text"
            ),
            /*
             * секция «Поведение»
             */
            Loc::getMessage('SCROLLUP_OPTIONS_SECTION_ACTION'),
            array(
                'speed',                                   // имя элемента формы
                Loc::getMessage('SCROLLUP_OPTIONS_SPEED'), // поясняющий текст — «Скорость прокрутки»
                'normal',                                  // значение по умолчанию «normal»
                array(
                    'selectbox',                           // тип элемента формы — <select>
                    array(
                        'slow'   => Loc::getMessage('SCROLLUP_OPTIONS_SPEED_SLOW'),
                        'normal' => Loc::getMessage('SCROLLUP_OPTIONS_SPEED_NORMAL'),
                        'fast'   => Loc::getMessage('SCROLLUP_OPTIONS_SPEED_FAST')
                    )
                )
            )
        )
    )
);

/*
 * Создаем форму для редактирвания параметров модуля
 */
$tabControl = new CAdminTabControl(
    'tabControl',
    $aTabs
);

$tabControl->begin();
?>
<form action="<?= $APPLICATION->getCurPage(); ?>?mid=<?=$module_id; ?>&lang=<?= LANGUAGE_ID; ?>" method="post">
    <?= bitrix_sessid_post(); ?>
    <?php
    foreach ($aTabs as $aTab) { // цикл по вкладкам
        if ($aTab['OPTIONS']) {
            $tabControl->beginNextTab();
            __AdmSettingsDrawList($module_id, $aTab['OPTIONS']);
        }
    }
    $tabControl->buttons();
    ?>
    <input type="submit" name="apply" 
           value="<?= Loc::GetMessage('SCROLLUP_OPTIONS_INPUT_APPLY'); ?>" class="adm-btn-save" />
    <input type="submit" name="default"
           value="<?= Loc::GetMessage('SCROLLUP_OPTIONS_INPUT_DEFAULT'); ?>" />
</form>

<?php
$tabControl->end();

/*
 * Обрабатываем данные после отправки формы
 */
if ($request->isPost() && check_bitrix_sessid()) {

    foreach ($aTabs as $aTab) { // цикл по вкладкам
        foreach ($aTab['OPTIONS'] as $arOption) {
            if (!is_array($arOption)) { // если это название секции
                continue;
            }
            if ($arOption['note']) { // если это примечание
                continue;
            }
            if ($request['apply']) { // сохраняем введенные настройки
                $optionValue = $request->getPost($arOption[0]);
                if ($arOption[0] == 'switch_on') {
                    if ($optionValue == '') {
                        $optionValue = 'N';
                    }
                }
                if ($arOption[0] == 'jquery_on') {
                    if ($optionValue == '') {
                        $optionValue = 'N';
                    }
                }
                Option::set($module_id, $arOption[0], is_array($optionValue) ? implode(',', $optionValue) : $optionValue);
            } elseif ($request['default']) { // устанавливаем по умолчанию
                Option::set($module_id, $arOption[0], $arOption[2]);
            }
        }
    }

    LocalRedirect($APPLICATION->getCurPage().'?mid='.$module_id.'&lang='.LANGUAGE_ID);

}
?>
<?php
/*
 * Файл local/modules/scrollup/lang/ru/options.php
 */

$MESS['SCROLLUP_OPTIONS_TAB_GENERAL']    = 'Основные настройки'; // Первая вкладка «Основные настройки»
$MESS['SCROLLUP_OPTIONS_SWITCH_ON']      = 'Включить прокрутку';
$MESS['SCROLLUP_OPTIONS_JQUERY_ON']      = 'Подключить jQuery';

$MESS['SCROLLUP_OPTIONS_TAB_ADDITIONAL'] = 'Дополнительные настройки'; // Вторая вкладка «Дополнительные настройки»
$MESS['SCROLLUP_OPTIONS_SECTION_VIEW']   = 'Внешний вид'; // секция «Внешний вид»
$MESS['SCROLLUP_OPTIONS_WIDTH']          = 'Ширина (пикселей)';
$MESS['SCROLLUP_OPTIONS_HEIGHT']         = 'Высота (пикселей)';
$MESS['SCROLLUP_OPTIONS_RADIUS']         = 'Радиус (пикселей)';
$MESS['SCROLLUP_OPTIONS_COLOR']          = 'Цвет фона';
$MESS['SCROLLUP_OPTIONS_SECTION_LAYOUT'] = 'Положение на странице'; // секция «Положение на странице»
$MESS['SCROLLUP_OPTIONS_POSITION']       = 'Положение кнопки';
$MESS['SCROLLUP_OPTIONS_SIDE_LEFT']      = 'Слева';
$MESS['SCROLLUP_OPTIONS_SIDE_RIGHT']     = 'Справа';
$MESS['SCROLLUP_OPTIONS_INDENT_BOTTOM']  = 'Отступ снизу (пикселей)';
$MESS['SCROLLUP_OPTIONS_INDENT_SIDE']    = 'Отступ сбоку (пикселей)';
$MESS['SCROLLUP_OPTIONS_SECTION_ACTION'] = 'Поведение'; // секция «Поведение»
$MESS['SCROLLUP_OPTIONS_SPEED']          = 'Скорость прокрутки';
$MESS['SCROLLUP_OPTIONS_SPEED_SLOW']     = 'Низкая';
$MESS['SCROLLUP_OPTIONS_SPEED_NORMAL']   = 'Средняя';
$MESS['SCROLLUP_OPTIONS_SPEED_FAST']     = 'Высокая';

$MESS['SCROLLUP_OPTIONS_INPUT_APPLY']    = 'Сохранить настройки';
$MESS['SCROLLUP_OPTIONS_INPUT_DEFAULT']  = 'Установить по умолчанию';

Страница настроек модуля теперь выглядит так:

Когда мы описывали код установки модуля, то привязались к событию OnBeforeEndBufferContent и указали метод appendJavaScriptAndCSS() класса Main как обработчик. Теперь настало время его написать:

<?php
/*
 * Файл local/modules/scrollup/lib/Main.php
 */

namespace ScrollUp;

use Bitrix\Main\Config\Option;
use Bitrix\Main\Page\Asset;

class Main {

    public function appendJavaScriptAndCSS() {

        // прокрутка будет работать только в публичной части
        if (!defined('ADMIN_SECTION') && ADMIN_SECTION !== true) {
            $module_id = pathinfo(dirname(__DIR__))['basename'];
            $options = json_encode(
                array(
                    'switch_on'     => Option::get($module_id, 'switch_on', 'Y'),
                    'width'         => Option::get($module_id, 'width', '50'),
                    'height'        => Option::get($module_id, 'height', '50'),
                    'radius'        => Option::get($module_id, 'radius', '50'),
                    'color'         => Option::get($module_id, 'color', '#bf3030'),
                    'side'          => Option::get($module_id, 'side', 'left'),
                    'indent_bottom' => Option::get($module_id, 'indent_bottom', '10'),
                    'indent_side'   => Option::get($module_id, 'indent_side', '10'),
                    'speed'         => Option::get($module_id, 'speed', 'normal')
                )
            );
            Asset::getInstance()->addCss('/bitrix/css/'.$module_id.'/style.css');
            // подключить библиотеку jQuery?
            if (Option::get($module_id, 'jquery_on', 'N') == 'Y') {
                \CJSCore::init(array('jquery2'));
            }
            Asset::getInstance()->addString(
                "<script id='".$module_id."-params' data-params='".$options."'></script>",
                true
            );
            Asset::getInstance()->addJs('/bitrix/js/'.$module_id.'/script.js');
            
        }
    }

}
<?php
/*
 * Файл local/modules/scrollup/include.php
 */

Bitrix\Main\Loader::registerAutoloadClasses(
    'scrollup',
    array(
        'ScrollUp\\Main' => 'lib/Main.php',
    )
);

Осталось только написать js-код для прокрутки страницы наверх и задать css-стили для кнопки:

/*
 * Файл local/modules/scrollup/install/assets/scripts/script.js
 */

$(function() {

    var params = $('#scrollup-params').data().params;

    if (params.switch_on == 'Y') {

        var style  = 'width: ' + params.width + 'px;';
            style += 'height: ' + params.height + 'px;';
            style += 'border-radius: ' + params.radius + 'px;';
            style += 'background-color: ' + params.color + ';';
            style += 'bottom: ' + params.indent_bottom + 'px;';
            style += params.side + ': ' + params.indent_side + 'px;';

        var speed = 600;
        if (params.speed == 'slow') {
            speed = 300;
        } else if (params.speed == 'fast'){
            speed = 1000;
        };

        $('body').append('<div id="scrollup-button" style="' + style +'"></div>');

        var button = $('#scrollup-button');
        $(window).on('load', function() {
            if ($(this).scrollTop() > 300) {
                button.fadeIn(600);
            }
        });

        $(window).on('scroll', function() {
            if ($(this).scrollTop() > 300) {
                button.fadeIn(600);
            } else {
                button.fadeOut(600);
            };
        });

        button.on('click', function() {
            $('html, body').animate({
                scrollTop: 0
            }, speed);
        });

    };

});
/*
 * Файл local/modules/scrollup/install/assets/styles/style.css
 */

#scrollup-button {
    position: fixed;
    cursor: pointer;
    display: none;
}
#scrollup-button:before {
    content: "";
    width: 0;
    height: 0;
    border-left: 15px solid transparent;
    border-right: 15px solid transparent;
    border-bottom: 25px solid #fff;
    margin: 9px auto 0;
    display: block;
}

Дополнительно

Поиск: CMS • OnBeforeEndBufferContent • Web-разработка • doInstall • doUninstall • step.php • unstep.php • version.php • Битрикс • Модуль • Прокрутка • Событие • Установка • registerAutoloadClasses • registerModule • unRegisterModule • registerEventHandler • unRegisterEventHandler • CopyDirFiles • deleteDirectory

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.