Итак после первых плагинов для ВордПресс и джумла пришла пора сделать что-то похожее в Битрикс.

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

И вот так получилось, что свежие мозги прошлись по ВордПрессу, Джумла и теперь взялись за Битрикс.

Сразу хочу сказать, что привыкнуть можно к любой CMS, все дело в обстоятельствах и наличии времени и желания.

Главное отличие отечественной CMS - оплата вперед

Итак не нужные проблемы у Битрикс начинаются уже на этапе установки, разработчики как бы говорят вам - нафига ты сюда лезешь (это наша корова и мы сами доить ее будем).

Проблемы с установкой

Имеется ввиду, что так называемая демо версия (на месяц) виснет при установке и до конца ну никак не доходит.

Мы сначала подумали, что это потому, что мы устанавливаем на локалхост или потому, что это демо версия, но оказалось в последствие, что так и должно быть. То есть и при установке демо или при установке нового сайта в рабочем варианте Битрикс - установка зависала на разных этапах по непонятным причинам.

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

В нашем случае установка падала в файле random.php в функции getStringByCharsets:

Скрытый текст
public static function getStringByCharsets($length, $charsetList)
{
	$charsetVariants = strlen($charsetList);
	/*$randomSequence = static::getBytes($length); // 117 строчка$result = '';
    for ($i = 0; $i < $length; $i++)
    {
    	$randomNumber = ord($randomSequence[$i]);
    	$result .= $charsetList[$randomNumber % $charsetVariants];
    }*/
  return "sdfdsfsdfdsfd";//$result;
}

Как видно выше мы тупо закомментировали почти весь код и просто возвращаем теперь не рандомную какую-то последовательность символов, а просто от балды константу "sdfdsfsdfdsfd".

И это сработало установка прошла далее гладко. О чем это говорит? Тестирование своих продуктов в битрикс "оставляем желать лучшего".

Но как мы знаем любая CMS это просто набор файлов php и некоторых других типов файлов, расписанных по разным каталогам по задуманной разработчиками какой-то их субъективной логике.

Таким образом мы копируем один рабочий сайт на Битриксе к себе на локалхост. Он заводится в целом без проблем, мы его обновляем из админки, все пока хорошо.

Огромное количество файлов

Но вот, что бросается в глаза, в чем отличие Битрикс, это огромное количество файлов и каталогов, у нас при скачке получилось около 230 тысяч. Соответственно это заняло не просто большое количество времени, а огромное. Пришло дома , где интернет 100МБс, скачать на диск и уже на работе с диска устанавливать. Это я к тому, что с джумлой и вордпресс у вас таких проблем не возникает.

Огромное количество таблиц в базе данных

Но без базы данных ничего не работает (как мы знаем) и это отдельная проблема, так как в Битрикс и количество таблиц в базе данных очень много, больше 200. И нам пришлось скачивать базу частями по несколько таблиц, так как phpmyadmin например не мог загрузить сразу всю базу целиком из файла sql. По другому мы не знали как, но это возможно от не знания, как можно.

Все это опять к вопросу, что в этом не было бы необходимости, если бы установка работала нормально.

Переходим к изучению как устроен битрикс

Сразу выясняем, что есть новое ядро D7 и есть старое и вроде как живут они вместе.

Есть каталог bitrix где все, что относится к ядру Битрикс и там лучше не располагать свои самопальные компоненты и модули ибо они затрутся при обновлении Битрикс. А где располагать тогда? Лучше во вновь придуманном каталоге local. Так мы и сделаем.

Много сайтов - один движок, одна база данных

У Битрикс есть своя особенность. Битрикс взял за идею предоставлять разработчику создавать неограниченное количество сайтов на одном движке Битрикс и в одной базе данных, то есть в одной админке. Хорошо это или плохо?... Платишь ты за движок один раз, а пользуешься движком во всех сайтах, вроде как не так обидно.

Но вот надо тебе перенести один сайт на другой движок и как-то надо отделить данные других сайтов, а база одна, таблицы общие и вроде как сразу проблема.

Нюансы установки и удаления модулей в битрикс

Итак, в битрикс надо писать инсталлятор модуля самому (в отличии от вордпресс и джумла например). А именно для этого создается каталог install (как часть состава вашего модуля), где вы и управляете логикой установки и удаления модуля, сами пишете какие файлы в какие папки копировать. То есть вы можете скопировать куда и что угодно и это как-то не есть правильно (бесконтрольно).

События

Тут как и во всех движках можно подписаться на события, которые испускают нужные нам компоненты или модули. Нас например заинтересовал OnAdminSaleOrderViewDraggable. Нам это надо, чтобы получить содержание открываемого заказа и сохранить данные заказа в своем модуле.

init.php

Отличие Битрикс от ВордПресса и джумлы ещё в том, что часть своего кода приходится писать в общих разделяемых файлах, а именно у нас конкретно в local\php_interface\init.php. Как я понял init.php предназначен для подключения своих модулей и компонент.

Таким образом нет полной изоляции от действий других разработчиков, то есть другой разработчик также открывает init.php, добавляет свой код, видит ещё наш код, думает: не из-за него ли глючит его сайт и конечно же удаляет наш код или временно отключает...

Надо учитывать, что если вы создадите init.php каталоге local/php-interface, то в bitrix/php_interface он вызываться уже не будет.

В init.php нам пришлось добавить строчку кода:

$request = \Bitrix\Main\Context::getCurrent()->getRequest();

if( $request->isAdminSection())
{
	if( $request->getRequestedPage() == '/bitrix/admin/sale_order_view.php' )
		require_once( $_SERVER['DOCUMENT_ROOT'] . '/local/modules/paymentacceptance/autoload.php');
}

Заказ а админке

Вот тут надо сказать, что в битрикс как и в ВордПресс и как в джумле для админки заказа есть обратная связь, то есть можно подписаться на событие при открытии заказа, получить состав заказа и добавить на форму свой визуальный блок:

Скрытый текст
<?php

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

Loc::loadMessages(__FILE__);

$ff = CJSCore::Init(array("jquery"));

$loaded = Bitrix\Main\Page\Asset::getInstance()->addJs('/local/modules/paymentacceptance/js/jquery-ui.js');
$loaded = Bitrix\Main\Page\Asset::getInstance()->addJs('/local/modules/paymentacceptance/js/bit_drv_kkt.js');

$APPLICATION->SetAdditionalCSS("/local/modules/paymentacceptance/css/bit_drv_kkt.css");


\Bitrix\Main\EventManager::getInstance()->addEventHandler("main", "OnAdminSaleOrderViewDraggable", array("PaymentAcceptance123", "onInit"));


class PaymentAcceptance123
{
	public static function onInit()
	{

		return array("BLOCKSET" => "PaymentAcceptance123",
			"getScripts"  => array("PaymentAcceptance123", "mygetScripts"),
			"getBlocksBrief" => array("PaymentAcceptance123", "mygetBlocksBrief"),
			"getBlockContent" => array("PaymentAcceptance123", "mygetBlockContent"),
			);
	}
		
	public static function mygetBlocksBrief($args)
		{
			$id = !empty($args['ORDER']) ? $args['ORDER']->getId() : 0;

			return array(
				'payments_pickup' => array("TITLE" => "Оплата заказа при самовывозе")
			);
		}
	
	public static function mygetScripts($args)
	{
		$BIT_KKT_TOKEN = COption::GetOptionString('paymentacceptance', 'BIT_KKT_TOKEN');
		if( $BIT_KKT_TOKEN != "")
			$BIT_KKT_TOKEN = "\nvar BIT_KKT_TOKEN='$BIT_KKT_TOKEN';";

		$BIT_BNK_TRM_TOKEN = COption::GetOptionString('paymentacceptance', 'BIT_BNK_TRM_TOKEN');
		if( $BIT_BNK_TRM_TOKEN != "")
			$BIT_BNK_TRM_TOKEN = "\nvar BIT_BNK_TRM_TOKEN='$BIT_BNK_TRM_TOKEN';";

		$BIT_PROG_URL = COption::GetOptionString('paymentacceptance', 'BIT_PROG_URL');
		if( $BIT_PROG_URL != "")
			$BIT_PROG_URL = "\nvar BIT_PROG_URL='$BIT_PROG_URL';";

		$ORDER = $args["ORDER"];

		$orderID = $ORDER->getId();
		if($orderID>0)
			$orderID = "\nvar orderID=$orderID;";
						
		return '<script type="text/javascript">'.$BIT_KKT_TOKEN.$BIT_BNK_TRM_TOKEN.$BIT_PROG_URL.$orderID.'</script>';
	}
		
	public static function mygetBlockContent($blockCode, $selectedTab, $args)
	{
		$result = '';
		$id = !empty($args['ORDER']) ? $args['ORDER']->getId() : 0;
		
		if ($selectedTab == 'tab_order')
		{
			$mdl = Loader::includeModule('paymentacceptance');
			
			if ( ! $mdl )
			{

			}

			if ($blockCode == 'payments_pickup')
			{
				$jsn = [];

				$ORDER=$args['ORDER'];

				$sum= $ORDER->getPrice();
				$isPaid = $ORDER->isPaid();
				$basket = $ORDER->getBasket();

				//$basket = $ORDER->getBasketItems();

				$id = \Bitrix\Main\Engine\CurrentUser::get()->getId();
				$bb = \Bitrix\Main\Engine\CurrentUser::get()->isAdmin();
				$login = \Bitrix\Main\Engine\CurrentUser::get()->getLogin();
				$fio = \Bitrix\Main\Engine\CurrentUser::get()->getFullName();
				
				$purchases=[];
				foreach( $basket as $kk => $itm)
				{
					$item=[];
					$item["productName_1030"]= $itm->getField('NAME');
					$item["price_1079"]= $itm->getPrice();
					$item["qty_1023"]= $itm->getQuantity();
					//$item["getWeight"]= $itm->getWeight();
					$item["getVatRate"] = $itm->getVatRate();
					$item["unit_2108"]=0;
					$item["paymentFormCode_1214"]=2;
					$item["productTypeCode_1212"]=3;
					$item["tax_1199"]= 6;
					//$item["additionalAttribut_1191"] = "что-то дополнительное";
					
					$purchases[] = $item;
				}
				$jsn ["purchases"] = $purchases;


				$jsn ["cashierInn_1203"] = $fio;
				$jsn ["taxationType_1055"] = 5;
				$jsn ["receiptType_1054"] = 1;
				//$jsn ["sendToEmail_1008"] = "";
				$jsn ["electronically"] = false;

				$json_data = json_encode($jsn ,JSON_PRETTY_PRINT| JSON_UNESCAPED_UNICODE);
				$result = 'Заказ № '.$id.'<BR>Сумма к оплате: <span id="k_oplate">'.$sum.'</span>&nbsp;<div id="paymentBtns"><button id="btnCash">Наличными</button> <button id="btnECash">Банковской картой</button></div><br><textarea id="json_data" style="width:100%">'.$json_data.'</textarea>';
			}
		}
		$aaaa= 123;
		return $result;
	}
}

У нас тут реализовано например оплата наличными или по карте при самовывозе.

На гитхабе мы как обычно выложили этот модуль для битрикс, можно скачать, установить и даже пользоваться https://github.com/PavelDorofeev/API-receipt-fiscalization-for-CMS-and-CRM.

Сделали небольшое видео? если кому вдруг стало интересно, так как всегда лучше один раз увидеть, чем 10 раз прочитать. Модуль бесплатный, думаю тут никакой рекламы нет.

Убрал видео, т.к. минусует кто-то, наверное из-за видео, странно и не понятно...

Что осталось из непонятого, можно ли было сделать как-то проще и не городить такой огород....

Вопрос знатокам:

  1. Можно ли не редактировать init.php, а как-то добавить из админки старт своего модуля, чтобы он автоматически загружался?

Немного подумав найден вполне приличный способ не править исходники Битрикс нигде, но это уже в комментариях смотрите.

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


  1. Aineko
    18.09.2024 10:32
    +4

    Изучайте документацию по модулям.

    модули из папки /local/modules/ нужно оформить в соответсвии с документацией, установить из админки и у них будет свой автолоад без модификации init.php

    подписка на события у таких модулей происходит по другому - при установке самого модуля

    https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&LESSON_ID=4809&LESSON_PATH=3913.3435.4609.4809


    1. kkmspb Автор
      18.09.2024 10:32

      Спс


    1. kkmspb Автор
      18.09.2024 10:32

      Чтобы модуль автоматом грузился надо, чтобы кто-то сделал includeModule. Автолоуд сам по себе не произойдет. Я пока нашел только вариант при установке модуля подписаться на событие например OnProlog и там в обработчике система вызовет includeModule.


      1. Mausglov
        18.09.2024 10:32

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


        1. kkmspb Автор
          18.09.2024 10:32

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

          Да можно про OnProlog забыть и сразу подписаться на OnAdminSaleOrderViewDraggable (это как раз на странице заказа в админке) и тут и состав заказа полностью передается через параметр:

          $eventManager->registerEventHandler(  "main", "OnAdminSaleOrderViewDraggable",
             $this->MODULE_ID,
             "paymentacceptance", "onInit");

          Хочу сказать, что в битрикс по факту можно обойтись одним модулем (и это гут), а в вордпрессе и джумле пришлось делать по 2 сущности.


      1. thekingoftheworld
        18.09.2024 10:32

        "Автолоуд" произойдет, если модуль установлен.


    1. kkmspb Автор
      18.09.2024 10:32

      подписка на события у таких модулей происходит по другому - при установке самого модуля

      Да теперь дошло. Именно так - в DoInstall.


  1. w0lf
    18.09.2024 10:32
    +1

    1. Можно ли не редактировать init.php, а как-то добавить из админки старт своего модуля, чтобы он автоматически загружался?

    Конечно можно. Добавьте в корень модуля файл include.php , где пропишите какие классы должны быть загружены автолоадом:

    CModule::AddAutoloadClasses('mlwebformsantispam', [
        'Multiline\MlWebFormsAntispam\MlWebFormsASProc' => 'lib/mlwebformsantispamprocessor.php',
        '\Multiline\MlWebFormsAntispam\MlWebFormsASProc' => 'lib/mlwebformsantispamprocessor.php',
    ]);


    1. kkmspb Автор
      18.09.2024 10:32

      Добавьте в корень модуля файл include.php

      Спасибо за наводку. Но чего-то include.php никем не вызывается (отладчиком смотрю), пойду почитаю немного доки.

      из папки local\modules похоже ни один модуль через include.php не аутолодится...


      1. w0lf
        18.09.2024 10:32

        А вообще модуль в Битрикс корректно установлен, в таблице b_modules он есть с датой активации?


        1. kkmspb Автор
          18.09.2024 10:32

          А вообще модуль в Битрикс корректно установлен, в таблице b_modules он есть с датой активации?

          Нормально устанавливается и деинсталлируется. В b_module он есть (paymentacceptance 2024-09-18 14:10:23 )


          1. kkmspb Автор
            18.09.2024 10:32

            DoInstall() и DoUnInstall() срабатывают, может туда регистрацию автозагрузки прописать?


    1. kkmspb Автор
      18.09.2024 10:32

      Конечно можно. Добавьте в корень модуля файл include.php , где пропишите какие классы должны быть загружены автолоадом:

      Похоже это совсем не то, что я хотел. Получается, что include.php вызывается, когда мы выполняем Loader::includeModule('paymentacceptance'); , то есть мне надо все-равно где-то в коде прописать Loader::includeModule('paymentacceptance'); - правильно?

      И чего-то я в базе данных не нашел, где хранятся настройки автозагрузки (модулей, классов и т.д.)

      И еще у меня нюанс, что модуль для админки пишу, может это важно...


      1. w0lf
        18.09.2024 10:32

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


        1. kkmspb Автор
          18.09.2024 10:32

          Мы тоже разрабатываем модули у которых есть часть, работающая в админке Битрикса, ничего дополнительно вручную вызывать не нужно, корректно написанный в соответствие с документацией модуль подключается в админку автоматически

          Я за вас рад конечно, но проблемка для меня не решена. Если бы вы поконкретнее показали кто и когда в коде у вас вызывает include.php было бы очень замечательно. А так у меня есть подозрения, что все равно надо править файл init.php. По интернету помониторил не нашел решения.


          1. kkmspb Автор
            18.09.2024 10:32

            Похоже разобрался как обойтись без правки init.php!

            Надо при установке модуля в методе DoInstall() подписаться на событие например OnProlog модуля main.

            		$eventManager = \Bitrix\Main\EventManager::getInstance(); 
            		
                    $bb = $eventManager->registerEventHandler(  "main",
                       "OnProlog",
                       $this->MODULE_ID,
                       "paymentacceptance",
                       "onProlog"
                    );

            В этом случае система в таблице b_module_to_module зарегистрирует наше событие.

            Потом открывая страницу будет испускаться событие OnProlog для нашего модуля paymentacceptance. Но перед этим система попытается загрузить модуль сначала и будет вызван include.php в каталоге нашего модуля. А тут мы уже знаем, что делать.

            Главное, что это работает! И не надо править исходники ядра битрикс.


            1. Mausglov
              18.09.2024 10:32

              Потом открывая страницу будет испускаться событие OnProlog для нашего модуля paymentacceptance

              Нет, неверно. Будет срабатывать событие OnProlog для модуля main. А поскольку Вы зарегистрировали обработчик для этого события, и при регистрации указали на свой модуль, то Ваш модуль будет подключен перед вызовом обработчика.

              Вам никто не мешает для своего модуля сделать событие OnProlog - соответственно, обработчик на него можно будет зарегистрировать как:

              $eventManager->registerEventHandler(  "yourmodule", "OnProlog", ... );

              События описаны в этой части курса. Ссылки в конце тоже полезны ( в чём-то даже полезнее самой главы)


              1. kkmspb Автор
                18.09.2024 10:32

                Нет, неверно. Будет срабатывать событие OnProlog для модуля main. А поскольку Вы зарегистрировали обработчик для этого события, и при регистрации указали на свой модуль, то Ваш модуль будет подключен перед вызовом обработчика.

                Я с вами не согласен. Событие OnProlog для модуля main не существует.

                Просто всегда стандартно при загрузки выполняется код, который читает записи в базе данных (в таблице b_module_to_module ). Находит как в коде ниже обработчики (связи с другими модулями) для "main" и "OnProlog" и вызывает их связанные методы через ExecuteModuleEventEx. Просто событиями обычно принято называть что-то, что генерирует ОС, а тут просто зачем-то решили событиями обозвать (не суть).

                bitrix\modules\main\include\prolog_before.php

                bitrix\modules\main\include.php

                CMain::PrologActions(); - это не событие, а просто вызов статического метода класса.

                Далее:

                foreach (GetModuleEvents("main", "OnProlog", true) as $arEvent)
                {
                	ExecuteModuleEventEx($arEvent);
                }

                то Ваш модуль будет подключен перед вызовом обработчика

                Тут не спорю, в этом и есть весь смысл, т.к. далее и будет вызван include.php в каталоге вашего модуля. Но сам по себе include.php он никак не вызовется.

                Вам никто не мешает для своего модуля сделать событие OnProlog - соответственно, обработчик на него можно будет зарегистрировать как:

                $eventManager->registerEventHandler( "yourmodule", "OnProlog", ... );

                Вот где как ни в в DoInstall() установщика модуля это сделать? И только не yourmodule, а так:

                $eventManager->registerEventHandler(  "main", "OnProlog",
                           $this->MODULE_ID,
                           "paymentacceptance", "onProlog");
                

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

                Но честно говоря документация битрикс мне не заходит, как-то много красивых слов, когда все просто на самом деле.


            1. w0lf
              18.09.2024 10:32

              Для интереса посмотрел код коммерческих модулей из Marketplace Bitrix - в основном используют такой же подход, вешают на OnBeforeProlog модуля main. Многие даже в "старом" стиле через RegisterModuleDependences а не registerEventHandler.


      1. Mausglov
        18.09.2024 10:32

        И чего-то я в базе данных не нашел, где хранятся настройки автозагрузки (модулей, классов и т.д.)

        В файле include.php модуля Вы и описываете всё, что относится к загрузке модуля - регистрация классов в автозагрузку, подключение модулей, от которых зависит Ваш модуль, языковые фразы.


  1. voidstrx
    18.09.2024 10:32

    У меня тоже висла установка Битрикс, пока не исправил конфиги mysql. Устанавливал на wsl debian.


    1. kkmspb Автор
      18.09.2024 10:32

      пока не исправил конфиги mysql.

      Да mysql.ini я тоже правил, увеличивал таймауты и лимиты памяти, но мне не помогло.


      1. voidstrx
        18.09.2024 10:32

        transaction-isolation = READ-COMMITTED
        innodb_flush_log_at_trx_commit = 2 //без этой строчки всё висло
        innodb_flush_method = O_DIRECT
        thread_cache_size = 4
        innodb_strict_mode=OFF


        1. kkmspb Автор
          18.09.2024 10:32

          innodb_flush_log_at_trx_commit = 2 //без этой строчки всё висло

          Попробовал, у меня =2 прибило локальную базу данных так, что пришлось переустанавливать все заново


  1. Psykyler
    18.09.2024 10:32
    +2

    Не лезь туда, оно тебя сожрёт


    1. kkmspb Автор
      18.09.2024 10:32

      Не лезь туда, оно тебя сожрёт

      Не превращайте хабр во флуд


  1. kkmspb Автор
    18.09.2024 10:32

    1. А, что в битрикс нельзя установить чужой модуль из zip файла в админке? Надо только по ftp закачивать и распаковывать самому?

    2. Добавить в репозиторий (маркетплейс) битрикс свой модуль - это реально?


    1. w0lf
      18.09.2024 10:32

      1. Можно загрузить zip файл через админку, через управление структурой, там же и распаковать.

      2. Можно добавить модуль в Marketplace, мы это проходили, в принципе ничего сложного.