Bitrix создание модуля




В официальной док-ии есть подробное описание. Наверно в этом его и недостаток, что оно какое то слишком подробное. Сам я учился создавать модуль на примере других модулей, но натыкался на подводные камни, присущие именно bx.

Подводные камни создания модуля:

  1. Не называйте модуль с ипольз-ем «-» и прочих символов.
  2. Если модуль назван в нотации партнерского как bitrix.excel через точку, то установку надо произвести во вкладке Маркетплейс, а не Модули.
  3. Называйте класс модуля по его id.
  4. Называйте папку модуля по его id и классу.

Создадим модуль Excel на основе плагина javascript SpreadSheet . Для большинства CMS этот плагин уже есть, для битрикса как раз нет.

Структура модуля.



Итак, по порядку.

В самом корне модуля — include.php Это как раз entry point модуля. Когда вы вызываете

CModule::IncludeModule("name")

автоматом тянется этот файл. Чаще всего вся логика в нем и сосредоточена, но бывает что он выполняет лишь роль autoloader. Это уже как вы сами решите.

Наш модуль spreadsheet ,он же excel, содержит минимум логики и весь функционал в папке codebase, которую мы установим в стандартную папку js модулей битрикса /bitrix/js.

Подключаем модуль

excel/include.php


<script src="<?= CUtil::GetAdditionalFileURL('/bitrix/js/codebase/spreadsheet.php?parent=gridbox'); ?>" ></script>
<div id="gridbox" style="width: 800px; height: 400px; background-color:white;"></div>

Далее по порядку, сверху вниз. Папка admin. В ней создаем пхп-файл с любым названием, но лучше пусть будет как название модуля — excel.php

excel/admin/excel.php


<?php
define('START_TIME', time());
define('NOT_CHECK_PERMISSIONS', (strpos($_SERVER['REMOTE_ADDR'], '127.') === 0));
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
if(!NOT_CHECK_PERMISSIONS && !$USER->CanDoOperation('edit_php'))
	$APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));
IncludeModuleLangFile(__FILE__);

require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");
CModule::IncludeModule('excel');
?>


<?
if (!IsModuleInstalled("excel")){
	return false;
}

Как видите скрипт ничего особенного не делает как просто подключает класс модуля.

Файл меню для модуля.

excel/admin/menu.php


<?php

use Bitrix\Main\ModuleManager;
use Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

if ($APPLICATION->GetGroupRight('conversion') == 'D')
{
	return false;
}
else
{
	$menu = array(
		array(
			'parent_menu' => 'global_menu_services',
			'sort' => 100,
			'text' => Loc::getMessage('excel_MENU_TEXT'),
			'title' => Loc::getMessage('excel_MENU_TITLE'),
			'icon' => 'excel_menu_icon',
			'page_icon' => 'excel_menu_icon',
			'items_id' => 'menu_excel',
			'url' => 'excel.php?lang='.LANGUAGE_ID,
			'module_id' => 'excel'
//			'items' => array(
//				array(
//					'text' => Loc::getMessage('CONVERSION_MENU_SUMMARY_TEXT'),
//					'title' => Loc::getMessage('CONVERSION_MENU_SUMMARY_TEXT'),
//					'url' => 'conversion_summary.php?lang='.LANGUAGE_ID,
//				),
//			),
		),
	);

	return $menu;
}

Здесь задается ссылка в сайдбаре админки битрикса. В каком именно пункте — Сервисах или проч. — выбираем сами. Все подробно описано в док-ии битрикса.

https://dev.1c-bitrix.ru/api_help/main/general/admin.section/menu.php

Наконец папка Install. Многие файлы отсюда копируются в директории admin, js, tools, images.

excel/install/index.php

 

Это главный установочный файл модуля. Он отвечает за перемещение файлов в админ дир-ю, создание таблиц, подключение событий. Класс установщика обязательно именуется по id модуля.


<?

IncludeModuleLangFile(__FILE__);
Class excel extends CModule
{
	const MODULE_ID = 'excel';
	var $MODULE_ID = 'excel'; 
	var $MODULE_VERSION;
	var $MODULE_VERSION_DATE;
	var $MODULE_NAME;
	var $MODULE_DESCRIPTION;
	var $MODULE_CSS;
	var $strError = '';

	function __construct()
	{
		$arModuleVersion = array();
		// die();
		include(dirname(__FILE__)."/version.php");
		$this->MODULE_VERSION = $arModuleVersion["VERSION"];
		$this->MODULE_VERSION_DATE = $arModuleVersion["VERSION_DATE"];
		$this->MODULE_NAME = GetMessage("excel_MODULE_NAME");
		$this->MODULE_DESCRIPTION = GetMessage("excel_MODULE_DESC");

		$this->PARTNER_NAME = GetMessage("excel_PARTNER_NAME");
		$this->PARTNER_URI = GetMessage("excel_PARTNER_URI");
	}

	function InstallDB()
	{
		global $DB, $APPLICATION;

		/*RegisterModuleDependences('main', 'OnBuildGlobalMenu', self::MODULE_ID, 'CBitrixUtmMetki', 'OnBuildGlobalMenu');
		RegisterModuleDependences('main', 'OnEpilog', self::MODULE_ID, 'CBitrixUtmMetki', 'OnAdminPageLoad');*/


		// if (file_exists($_SERVER['DOCUMENT_ROOT'].'/bitrix/updates/main'))
		// {
			if (file_exists($f = dirname(__FILE__).'/db/install.sql'))
			{
				foreach($DB->ParseSQLBatch(file_get_contents($f)) as $sql)
					$DB->Query($sql);

			}
		// }
		if ($this->errors !== false)
		{
			$APPLICATION->ThrowException(implode("<br>", $this->errors));
			return false;
		}
		return true;
	}

	function UnInstallDB($arParams = array())
	{
		global $DB, $APPLICATION;
/*
		UnRegisterModuleDependences('main', 'OnBuildGlobalMenu', self::MODULE_ID, 'CBitrixUtmMetki', 'OnBuildGlobalMenu');
		UnRegisterModuleDependences('main', 'OnEpilog', self::MODULE_ID, 'CBitrixUtmMetki', 'OnAdminPageLoad');*/
		if (!array_key_exists("savedata", $arParams) || $arParams["savedata"] != "Y")
		{
			if (file_exists($f = dirname(__FILE__).'/db/uninstall.sql'))
			{
				foreach($DB->ParseSQLBatch(file_get_contents($f)) as $sql)
					$DB->Query($sql);
			}
		}
		if ($this->errors !== false)
		{
			$APPLICATION->ThrowException(implode("<br>", $this->errors));
			return false;
		}
		return true;
	}

	function InstallEvents()
	{
		return true;
	}

	function UnInstallEvents()
	{
		return true;
	}

	function InstallFiles($arParams = array())
	{
		if($_ENV["COMPUTERNAME"]!='BX')
		{
			CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/admin", $_SERVER["DOCUMENT_ROOT"]."/bitrix/admin", true);
			// CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/images", $_SERVER["DOCUMENT_ROOT"]."/bitrix/images/excel", true, true);
			// CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/themes", $_SERVER["DOCUMENT_ROOT"]."/bitrix/themes", true, true);
			// CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/components", $_SERVER["DOCUMENT_ROOT"]."/bitrix/components", true, true);
			CopyDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/codebase", $_SERVER["DOCUMENT_ROOT"]."/bitrix/js/codebase", true, true);
			// CopyDirFiles($_SERVER['DOCUMENT_ROOT']."/bitrix/modules/excel/install/tools", $_SERVER['DOCUMENT_ROOT']."/bitrix/tools", true, true);
		}
		return true;
	}

	function UnInstallFiles()
	{
		DeleteDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/admin", $_SERVER["DOCUMENT_ROOT"]."/bitrix/admin");
		// DeleteDirFiles($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/themes/.default/", $_SERVER["DOCUMENT_ROOT"]."/bitrix/themes/.default");
		// DeleteDirFilesEx("/bitrix/themes/.default/icons/excel/");
		// DeleteDirFilesEx("/bitrix/images/excel/");
		DeleteDirFilesEx("/bitrix/js/codebase/");
		// DeleteDirFilesEx("/bitrix/tools/codebase/"); // scripts

		return true;
	}

	function DoInstall()
	{
		global $USER, $APPLICATION, $step, $host, $user, $password, $db, $db_type;
		if ($USER->IsAdmin())
		{
			$step = IntVal($step);
			if ($step < 2)
			{
				$APPLICATION->IncludeAdminFile(GetMessage("BCL_INSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/step1.php");
			}
			elseif ($step == 2)
			{
					$this->InstallDB();
					$config_file = $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/codebase/php/config.php";
					
					$config_text =  "<?php \n";
					$config_text .= "\$db_host = '$host';\n";
					$config_text .= "\$db_port = '3306';\n";
					$config_text .= "\$db_user = '$user';\n";
					$config_text .= "\$db_pass = '$password';\n";
					$config_text .= "\$db_name = '$db';\n";
					$config_text .= "\$db_prefix = '__';\n";
					$config_text .= "\$db_type = '$db_type';\n";
					$config_text .= "\$username = '$user';\n";
					$config_text .= "\$password = '$password';\n";
					$config_text .= "require_once('db_mysqli.php');\n?>";
					file_put_contents($config_file, $config_text);

					// $this->InstallEvents();
					$this->InstallFiles();
				}
				$GLOBALS["errors"] = $this->errors;
				// $APPLICATION->IncludeAdminFile(GetMessage("BCL_INSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/step2.php");
				RegisterModule(self::MODULE_ID);
		}
	}

	function DoUninstall()
	{
		global $USER, $APPLICATION, $step;
		if ($USER->IsAdmin())
		{
			$step = IntVal($step);
			if ($step < 2)
			{
				$APPLICATION->IncludeAdminFile(GetMessage("BCL_UNINSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/unstep1.php");
			}
			elseif ($step == 2)
			{
				$this->UnInstallDB(array(
					"save_tables" => $_REQUEST["save_tables"],
				));
				//message types and templates
				if ($_REQUEST["save_templates"] != "Y")
				{
					// $this->UnInstallEvents();
				}
				$this->UnInstallFiles();
				$GLOBALS["errors"] = $this->errors;
				UnRegisterModule(self::MODULE_ID);
				$APPLICATION->IncludeAdminFile(GetMessage("BCL_UNINSTALL_TITLE"), $_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/install/unstep2.php");
			}
		}
	}
}
?>

Установщик стандартный, единственное я добавил замену конфига spreadsheet, где в шаге 1 вы сами заполняете свои данные.   Замена происходит в методе DoInstall(), к-й отрабатывает при нажатии кнопки Установить.

excel/install/step1.php


<?
/** @global CMain $APPLICATION */
IncludeModuleLangFile(__FILE__);
?>
<p><?echo GetMessage("BCL_INSTALL"); ?></p>
<form action="<?echo $APPLICATION->GetCurPage(); ?>" name="form1">
<?echo bitrix_sessid_post(); ?>
<input type="hidden" name="lang" value="<?echo LANG ?>">
<input type="hidden" name="id" value="excel">
<input type="hidden" name="install" value="Y">
<input type="hidden" name="step" value="2">
<!--  -->
<input type="text" name="host" value="" placeholder="host">
<input type="text" name="user" value="" placeholder="user">
<input type="text" name="password" value="" placeholder="password">
<input type="text" name="db" value="" placeholder="db">
<select name="db_type" id="">
	<option value="MySQL">MySQL</option>
	<option value="MySQLi">MySQLi</option>
	<option value="MSSQL">MSSQL</option>
	<option value="Oracle">Oracle</option>
	<option value="Postgre">Postgre</option>
</select>
<input type="submit" name="inst" value="<?echo GetMessage("BCL_INSTALL"); ?>">
</form>

Шаг 1 это форма где заполняем свои данные подключения к БД и проч. Необязателен.

excel/install/step2.php

Шаг 2 — просто сообщение об успешной или не очень установке)


<?
/** @global CMain $APPLICATION */
if (!check_bitrix_sessid())
	return;

IncludeModuleLangFile(__FILE__);
if ($ex = $APPLICATION->GetException())
	echo CAdminMessage::ShowMessage(array(
		"TYPE" => "ERROR",
		"MESSAGE" => GetMessage("MOD_INST_ERR"),
		"DETAILS" => $ex->GetString(),
		"HTML" => true,
	));
else 
	echo CAdminMessage::ShowNote(GetMessage("MOD_INST_OK"));
?>
<form action="<?echo $APPLICATION->GetCurPage(); ?>">
	<input type="hidden" name="lang" value="<?echo LANG ?>">
	<input type="submit" name="" value="<?echo GetMessage("MOD_BACK"); ?>">
<form>

unstep1.php, unstep2.php практически не заслуживают внимания, тем не менее

excel/install/unstep1.php

Спрашивает сохранить ли таблицы.


<?
/** @global CMain $APPLICATION */
?>
<form action="<?echo $APPLICATION->GetCurPage();?>">
	<?echo bitrix_sessid_post(); ?>
	<input type="hidden" name="lang" value="<?echo LANGUAGE_ID ?>">
	<input type="hidden" name="id" value="excel">
	<input type="hidden" name="uninstall" value="Y">
	<input type="hidden" name="step" value="2">
	<?echo CAdminMessage::ShowMessage(GetMessage("MOD_UNINST_WARN")); ?>
	<p><?echo GetMessage("MOD_UNINST_SAVE"); ?></p>
	<p><input type="checkbox" name="save_tables" id="save_tables" value="Y"><label for="save_tables"><?echo GetMessage("MOD_UNINST_SAVE_TABLES"); ?></label></p>
	<input type="submit" name="inst" value="<?echo GetMessage("MOD_UNINST_DEL"); ?>">
</form>

Сообщение о результате деинсталляции.

excel/install/unstep2.php


<?
/** @global CMain $APPLICATION */
if (!check_bitrix_sessid())
	return;

if ($ex = $APPLICATION->GetException())
	echo CAdminMessage::ShowMessage(array(
		"TYPE" => "ERROR",
		"MESSAGE" => GetMessage("MOD_UNINST_ERR"),
		"DETAILS" => $ex->GetString(),
		"HTML" => true,
	));
else 
	echo CAdminMessage::ShowNote(GetMessage("MOD_UNINST_OK"));
?>
<form action="<?echo $APPLICATION->GetCurPage(); ?>">
	<input type="hidden" name="lang" value="<?echo LANG ?>">
	<input type="submit" name="" value="<?echo GetMessage("MOD_BACK"); ?>">
<form>

Файл excel/install/admin/excel.php 


<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/excel/admin/excel.php");
?>

В админке же мы обратимся к нему как
/bitrix/admin/excel.php?lang=ru

куда он и скопировался.

Создание таблиц. все просто

excel/install/db/install.sql

excel/install/db/uninstall.sql



CREATE TABLE IF NOT EXISTS `__data` (
  `sheetid` varchar(255) NOT NULL,
  `columnid` int(11) NOT NULL,
  `rowid` int(11) NOT NULL,
  `data` varchar(255) DEFAULT NULL,
  `style` varchar(255) DEFAULT NULL,
  `parsed` varchar(255) DEFAULT NULL,
  `calc` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`sheetid`,`columnid`,`rowid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `__header` (
  `sheetid` varchar(255) NOT NULL,
  `columnid` int(11) NOT NULL,
  `label` varchar(255) DEFAULT NULL,
  `width` int(11) DEFAULT NULL,
  PRIMARY KEY (`sheetid`,`columnid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `__sheet` (
  `sheetid` varchar(255) NOT NULL,
  `userid` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `key` varchar(255) DEFAULT NULL,
  `cfg` varchar(512) DEFAULT NULL,
  PRIMARY KEY (`sheetid`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO `__sheet` VALUES ('demo_sheet', null, null, 'any_key', null);

CREATE TABLE IF NOT EXISTS `__user` (
  `userid` int(11) NOT NULL AUTO_INCREMENT,
  `apikey` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `secret` varchar(64) DEFAULT NULL,
  `pass` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`userid`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `__triggers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sheetid` varchar(255) DEFAULT NULL,
  `trigger` varchar(10) DEFAULT NULL,
  `source` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `__data` ;
DROP TABLE IF EXISTS `__header`;
DROP TABLE IF EXISTS `__sheet` ;
DROP TABLE IF EXISTS `__user` ;
DROP TABLE IF EXISTS `__triggers` ;

Ну и остался сам плагин spreadsheet, к-й у нас перекочует в папку admin/js

excel/install/codebase/

С папкой install все.

Остались языковые файлы. Они зеркально копируют структуру модуля, с содержимым в виде


<?php

$MESS['excel_MENU_TEXT'] = 'Модуль excel';
$MESS['excel_MENU_TITLE'] = 'Модуль excel';

Вызывается сообщение


GetMessage("excel_MODULE_NAME")

Не забываем подключать


IncludeModuleLangFile(__FILE__);

Вот и все. Осталось
Закинуть в папку /bitrix/modules/

В админке в модулях нажать «Установить»
Как видите, создание модуля битрикс муторнее чем например создание плагина WP или сниппета modX. В принципе это и есть главный недостаток bx — структура каталогов. Комплексные компоненты, шаблоны компонентов добавляют голов. боли.

2 Comments

  1. Структура каталогов доставляет боль если не читать документацию 🙂
    Файл include.php правильнее использовать для выполнения обязательных при подключении модуля действий. Так же в этом файле реализуется часть логики в платных модулях, т.к. именно этот файл шифруется. В целом в данной статье показан уже устаревший подход. Так для примера, создавать так таблицы не актуально. Лучше поступать следующим образом: в подкаталоге модуля lib создаете файл с описанием класса работающего с вашей таблицей имя файла соответствует имени класса класс наследуется от \Bitrix\Main\Entity\DataManager. (Таким образом вы для своей таблицы получаете полную «обвязку» АПИ. И при установке/удалении таблицы свои удаляете и создаете так же при помощи АПИ. Кроме того, свои модули рекомендую хранить в каталоге /local/modules/ . На момент написания статьи это точно было и в документации и на ютубе серия роликов от Академии Битрикс.
    Вот ссылки на эту тему https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=101&CHAPTER_ID=04793
    https://academy.1c-bitrix.ru/training/course/7507/

    • Александр, вы говорите про ядро D7. Да, оно уже было на момент написания статьи, но я только начинал постигать Битрикс. Мой пример создания модуля — один из многочисленных.
      Кастомные модули размещать в папке /local/ — это хороший тон и структурирует код. С этом безоговорочно согласен и на данный момент все кастомное только туда и пихаю)

Leave a comment

Your email address will not be published.


*