Compare commits

..
10 Commits
Author SHA1 Message Date
Bellord e70a98e7b9 fix 2026-09-12 10:14:11 +03:00
Bellord 47271d9413 fix 2026-06-03 11:11:05 +03:00
bellord 207d793b07 fix 2025-11-23 14:17:17 +03:00
bellord 448edb8671 fix 2025-09-05 17:35:08 +03:00
bellord 4c2e56dd4c fix 2025-04-01 06:54:37 +03:00
bellord 2b6ebbf17d fix 2025-03-29 03:35:47 +03:00
bellord 1ab56ef3c4 fix 2025-03-19 04:49:12 +03:00
bellord 218eeff1ad fix 2024-10-07 18:52:00 +03:00
bellord af604aa607 fix 2024-10-06 23:09:22 +03:00
bellord d8b103fe33 fix 2024-07-07 12:39:20 +03:00
45 changed files with 739 additions and 359 deletions
+4 -4
View File
@@ -1,9 +1,9 @@
{ {
"id": "bx.null", "id": "bx.nullable",
"prefix": "bx_null", "prefix": "bx_nullable",
"namespace": "Bx\\Null", "namespace": "Bx\\Nullable",
"gitUrl": "https://bitbucket.org/bellord13/bx.null/", "gitUrl": "https://bitbucket.org/bellord13/bx.null/",
"version": "1.0.0", "version": "1.0.0",
"date": "2024-01-01 00:00:00", "date": "2026-01-01 00:00:00",
"deps": ["wt.core"] "deps": ["wt.core"]
} }
+199
View File
@@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
namespace Wt\Core\App;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use UnexpectedValueException;
/**
* Class ModuleCloner
*
* Обеспечивает функционал клонирования Bitrix модулей с автоматической
* заменой идентификаторов и пространств имен.
*/
class ModuleCloner
{
protected array $excludePatterns = [
'/\.git$/',
'/\.module\.json/',
'/clone\.php/',
'/ModuleCloner\.php/',
'/readme\.md/',
'/src\/\.env$/',
'/src\/config\.php$/',
];
public function __construct(
private readonly ModuleEntity $sourceEntity,
private readonly ModuleEntity $targetEntity
) {}
/**
* Основной метод клонирования модуля.
*
* @throws UnexpectedValueException
*/
public function clone(): void
{
$this->copyStructure();
$this->fixContent();
}
/**
* Копирует структуру папок и файлов из источника в цель.
*/
protected function copyStructure(): void
{
$this->copyFolderSafe(
$this->sourceEntity->getPath(),
$this->targetEntity->getPath()
);
}
/**
* Рекурсивное копирование папки с фильтрацией и динамическим переименованием.
*/
protected function copyFolderSafe(string $source, string $destination): void
{
if ($this->shouldExclude($source)) {
echo "Skip: $source" . PHP_EOL;
return;
}
if (is_dir($source)) {
$destination = $this->ensureDirectory($destination);
if ($destination === null) {
return;
}
$dir = dir($source);
while (false !== ($entry = $dir->read())) {
if ($entry !== '.' && $entry !== '..') {
$srcPath = $source . DIRECTORY_SEPARATOR . $entry;
$dstPath = $destination . DIRECTORY_SEPARATOR . $entry;
$dstPath = $this->renamePathSegment($dstPath);
$this->copyFolderSafe($srcPath, $dstPath);
}
}
$dir->close();
} else {
$this->copyFileSafe($source, $destination);
}
}
/**
* Копирует файл с сохранением времени модификации.
*/
protected function copyFileSafe(string $source, string $destination): void
{
$time = filemtime($source);
if (file_exists($destination) && filemtime($destination) >= $time) {
return;
}
if (copy($source, $destination)) {
touch($destination, $time);
}
}
/**
* Создает директорию, если она отсутствует.
*/
protected function ensureDirectory(string $path): ?string
{
if (file_exists($path)) {
if (is_dir($path)) {
return $path;
}
unlink($path);
}
return mkdir($path, 0777, true) ? $path : null;
}
/**
* Выполняет массовую замену строк в PHP файлах целевого модуля.
*/
protected function fixContent(): void
{
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($this->targetEntity->getPath()),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'php') {
$path = $file->getPathname();
$content = file_get_contents($path);
$original = $content;
$replacements = $this->getReplacements();
foreach ($replacements as $search => $replace) {
$content = str_replace($search, $replace, $content);
}
if ($original !== $content) {
file_put_contents($path, $content);
echo "Fixed: $path" . PHP_EOL;
}
}
}
}
/**
* Формирует карту замен на основе сущностей модулей.
*/
protected function getReplacements(): array
{
$s = $this->sourceEntity;
$t = $this->targetEntity;
$productS = ucfirst($s->getProductCode());
$productT = ucfirst($t->getProductCode());
$companyS = ucfirst($s->getCompanyCode());
$companyT = ucfirst($t->getCompanyCode());
return [
$s->getLangPrefix() => $t->getLangPrefix(),
$s->getId() => $t->getId(),
$s->getPrefix() => $t->getPrefix(),
$s->getNamespace() => $t->getNamespace(),
"$productS: $productS" => "$productT: $productT",
$productS => $productT,
$companyS => $companyT,
$s->getProductCode() => $t->getProductCode(),
$s->getCompanyCode() => $t->getCompanyCode(),
];
}
/**
* Переименовывает сегменты пути (папки) в соответствии с именами модулей.
*/
protected function renamePathSegment(string $path): string
{
$sourceLast = collect(explode('.', $this->sourceEntity->getId()))->last();
$targetLast = collect(explode('.', $this->targetEntity->getId()))->last();
$path = str_replace(ucfirst($sourceLast), ucfirst($targetLast), $path);
$path = str_replace(strtolower($sourceLast), strtolower($targetLast), $path);
return $path;
}
/**
* Проверяет, должен ли файл/папка быть исключен из копирования.
*/
protected function shouldExclude(string $path): bool
{
foreach ($this->excludePatterns as $pattern) {
if (preg_match($pattern, $path)) {
return true;
}
}
return false;
}
}
+12 -12
View File
@@ -2,22 +2,22 @@
IncludeModuleLangFile(__FILE__); IncludeModuleLangFile(__FILE__);
return array( return [
'MAIN' => array( 'MAIN' => [
'TITLE' => GetMessage('MAIN_OPTIONS_PARAMETERS'), 'TITLE' => GetMessage('MAIN_OPTIONS_PARAMETERS'),
'THEME' => 'Y', 'THEME' => 'Y',
'OPTIONS' => array( 'OPTIONS' => [
), ],
), ],
'TEST' => array( 'TEST' => [
'TITLE' => 'test', 'TITLE' => 'test',
'OPTIONS' => array( 'OPTIONS' => [
'TEST' => array( 'TEST' => [
'TITLE' => 'test_setting', 'TITLE' => 'test_setting',
'TYPE' => 'text', 'TYPE' => 'text',
'DEFAULT' => '', 'DEFAULT' => '',
), ],
), ],
), ],
); ];
+1 -1
View File
@@ -3,7 +3,7 @@
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php');
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_after.php'); require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_after.php');
$adminPage = new \Wt\Core\Admin\SiteSettingsAdminPage('bx.null', 'main'); $adminPage = new \Wt\Core\Admin\SiteSettingsAdminPage('bx.nullable', 'main');
$adminPage->render(); $adminPage->render();
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php'); require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php');
+2 -5
View File
@@ -1,5 +1,2 @@
<? <?php
$MESS['MAIN_OPTIONS_PARAMETERS'] = 'Общие'; $MESS['MAIN_OPTIONS_PARAMETERS'] = 'Общие';
$MESS['LOGO_IMAGE'] = 'Логотип сайта';
$MESS['CACHE_OPTIONS'] = 'Кеш';
$MESS['CACHE_STORAGE'] = 'Место хранения кеша';
+1 -1
View File
@@ -8,4 +8,4 @@ Loc::loadMessages(__FILE__);
return (new GlobalMenuItem()) return (new GlobalMenuItem())
->setSort(10) ->setSort(10)
->setTitle('Null Main'); ->setTitle('Nullable Main');
@@ -1,17 +1,17 @@
<?php <?php
use Bx\Null\ORM\NullTable; use Bx\Nullable\ORM\NullableTable;
use Wt\Core\Admin\TableAdminPage; use Wt\Core\Admin\TableAdminPage;
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin.php');
/** /**
* @var $ormTable NullTable * @var NullableTable $ormTable
*/ */
$ormTable = resolve(NullTable::class); $ormTable = resolve(NullableTable::class);
$tableAdminPage = new TableAdminPage($ormTable, $_REQUEST, '/bitrix/admin/bx_null.main.null_table.row.php'); $tableAdminPage = new TableAdminPage($ormTable, $_REQUEST, '/bitrix/admin/bx_nullable.main.nullable_table.row.php');
$tableAdminPage $tableAdminPage
->checkPermission() ->checkPermission()
->start() ->start()
@@ -1,2 +1,2 @@
<? <?php
$MESS['CONTEXT_PROFILE_DELETE_CONFIRM'] = 'Удалить %s?'; $MESS['CONTEXT_PROFILE_DELETE_CONFIRM'] = 'Удалить %s?';
@@ -7,7 +7,8 @@ Loc::loadMessages(__FILE__);
return (new GlobalMenuItem()) return (new GlobalMenuItem())
->setVisible(false)
->setSort(1300) ->setSort(1300)
->setTitle('Null Table') ->setTitle('Nullable Table')
->setIcon('iblock_menu_icon_iblocks') ->setIcon('iblock_menu_icon_iblocks')
->setUrl(); ->setUrl();
@@ -1,20 +1,17 @@
<? <?php
use Bx\Null\ORM\NullTable; use Bx\Nullable\ORM\NullableTable;
use Wt\Core\Admin\TableRowAdminPage; use Wt\Core\Admin\TableRowAdminPage;
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_after.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_after.php');
/** /**
* @var $ormTable NullTable * @var NullableTable $ormTable
*/ */
$ormTable = resolve(NullTable::class); $ormTable = resolve(NullableTable::class);
$AdminPageTableRow = new TableRowAdminPage($ormTable, $_REQUEST, '/bitrix/admin/bx_null.main.null_table.php'); $AdminPageTableRow = new TableRowAdminPage($ormTable, $_REQUEST, '/bitrix/admin/bx_nullable.main.nullable_table.php');
$AdminPageTableRow->checkPermission(); $AdminPageTableRow->checkPermission();
$AdminPageTableRow->start(); $AdminPageTableRow->start();
\CJSCore::Init('jquery');
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php');
@@ -1,2 +1,2 @@
<? <?php
$MESS['MAIN_OPTIONS_PARAMETERS'] = 'Общие'; $MESS['MAIN_OPTIONS_PARAMETERS'] = 'Общие';
@@ -7,7 +7,7 @@ Loc::loadMessages(__FILE__);
return (new GlobalMenuItem()) return (new GlobalMenuItem())
->setSort(1400) ->setSort(1400)
->setTitle('Null Table Row') ->setTitle('Nullable Table Row')
->setIcon('default_menu_icon') ->setIcon('default_menu_icon')
->setVisible(false) ->setVisible(false)
->setUrl(); ->setUrl();
+17 -17
View File
@@ -5,39 +5,39 @@ use Wt\Core\Admin\SiteSettingsAdminPage;
IncludeModuleLangFile(__FILE__); IncludeModuleLangFile(__FILE__);
/** /**
* @var $this SiteSettingsAdminPage * @var SiteSettingsAdminPage $this
*/ */
return array( return [
'MAIN' => array( 'MAIN' => [
'TITLE' => 'Общие сведения', 'TITLE' => 'Общие сведения',
'OPTIONS' => array( 'OPTIONS' => [
'ENABLE' => array( 'ENABLE' => [
'TITLE' => 'Enable module', 'TITLE' => 'Enable module',
'TYPE' => 'checkbox', 'TYPE' => 'checkbox',
'DEFAULT' => 'N', 'DEFAULT' => 'N',
'HINT' => '', 'HINT' => '',
), ],
'CONFIG' => array( 'CONFIG' => [
'TITLE' => 'Конфигурационные данные', 'TITLE' => 'Конфигурационные данные',
'HINT' => '', 'HINT' => '',
'TYPE' => 'content', 'TYPE' => 'content',
'INCLUDEFILE' => \Wt\Core\Tools::removeDocRoot(__DIR__ . '/include/config.php'), 'INCLUDEFILE' => \Wt\Core\Tools::removeDocRoot(__DIR__ . '/include/config.php'),
'SHOW_EDIT_BUTTON' => 'N', 'SHOW_EDIT_BUTTON' => 'N',
'DEFAULT' => '', 'DEFAULT' => '',
), ],
), ],
), ],
'DOCS' => array( 'DOCS' => [
'TITLE' => 'Docs', 'TITLE' => 'Docs',
'OPTIONS' => array( 'OPTIONS' => [
'DOCUMENTATION' => array( 'DOCUMENTATION' => [
'TITLE' => 'Documentation', 'TITLE' => 'Documentation',
'TYPE' => 'content', 'TYPE' => 'content',
'INCLUDEFILE' => \Wt\Core\Tools::removeDocRoot(__DIR__ . '/include/documentation.php'), 'INCLUDEFILE' => \Wt\Core\Tools::removeDocRoot(__DIR__ . '/include/documentation.php'),
'SHOW_EDIT_BUTTON' => 'N', 'SHOW_EDIT_BUTTON' => 'N',
'DEFAULT' => '', 'DEFAULT' => '',
), ],
), ],
), ],
); ];
+39 -7
View File
@@ -1,6 +1,6 @@
<?php <?php
/** /**
* @var $this Wt\Core\Admin\Templater * @var Wt\Core\Admin\Templater $this
*/ */
$moduleId = $this->getAdminPage()->getModuleId(); $moduleId = $this->getAdminPage()->getModuleId();
$app = app()::getInstance($moduleId); $app = app()::getInstance($moduleId);
@@ -9,9 +9,41 @@ $data['env'] = $app->env();
?> ?>
<table cellpadding="5" border="1" style="border-collapse: collapse; width: 100%"> <table cellpadding="5" border="1" style="border-collapse: collapse; width: 100%">
<? <?php
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
?><tr><td><?= $key ?></td><td><?= $value ?></td></tr><? ?><tr><td><?= $key ?></td><td><?= $value ?></td></tr><?php
} }
?></table><? ?></table>
<br><?php
?><table cellpadding="5" border="1" style="border-collapse: collapse; width: 100%">
<tr>
<?php
$initPhpSrc = getLocalPath('php_interface/init.php', BX_PERSONAL_ROOT);
$src = $app->module()->getSrc();
$html = "<div style=\"font-family: monospace; font-size: 0.9em; white-space: pre; color: grey;\">if(file_exists(\$_SERVER['DOCUMENT_ROOT'] . '$src/init.php'))
include_once \$_SERVER['DOCUMENT_ROOT'] . '$src/init.php';</div>";
?>
<td>
<?=$this->getCheckTemplate($app->isIncludeFileToInitPhp())?>
</td>
<td>
Модуль подключен в init.php
</td>
<td width="50%">
<?php
if($initPhpSrc){
?><a target="_blank" href="/bitrix/admin/fileman_file_edit.php?path=<?=urlencode($initPhpSrc)?>&full_src=Y">
<?=$initPhpSrc?>
</a><?php
} else {
?>init.php отсутствует<?php
}
?>
<br>
<?=$html?>
</td>
</tr>
</table>
<br>
+2 -11
View File
@@ -1,18 +1,9 @@
<?php <?php
use Wt\Core\Admin\TableAdminPage;
require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php'); require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_admin_before.php');
require($_SERVER['DOCUMENT_ROOT']. '/bitrix/modules/main/include/prolog_admin_after.php');
$adminPage = new \Wt\Core\Admin\SiteSettingsAdminPage('bx.nullable', 'main.settings');
CJSCore::Init('jquery');
CAjax::Init();
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");
$adminPage = new \Wt\Core\Admin\SiteSettingsAdminPage('bx.null', 'main.settings');
$adminPage->render(); $adminPage->render();
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php'); require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_admin.php');
@@ -1,2 +1,2 @@
<? <?php
$MESS['CONTEXT_PROFILE_DELETE_CONFIRM'] = 'Удалить %s?'; $MESS['CONTEXT_PROFILE_DELETE_CONFIRM'] = 'Удалить %s?';
+1 -1
View File
@@ -1,6 +1,6 @@
<?php <?php
use \Bitrix\Main\Localization\Loc; use Bitrix\Main\Localization\Loc;
use Wt\Core\Admin\GlobalMenuItem; use Wt\Core\Admin\GlobalMenuItem;
Loc::loadMessages(__FILE__); Loc::loadMessages(__FILE__);
+27 -54
View File
@@ -1,63 +1,36 @@
<?php <?php
declare(strict_types=1);
use Wt\Core\App\ModuleEntity;
use Wt\Core\App\ModuleCloner;
require './../wt.core/include.php'; require './../wt.core/include.php';
require './ModuleCloner.php';
$curPath = __DIR__; if (!isset($argv[1])) {
$newPath = realpath($argv[1]); echo "Error: Please provide the target module path as the first argument." . PHP_EOL;
$newEntity = __getModuleEntity($newPath); exit(1);
$nullEntity = __getModuleEntity(__DIR__);
function copy_folder($d1, $d2, $upd = true, $force = true, $exclude = []) {
if ( is_dir( $d1 ) ) {
$d2 = mkdir_safe( $d2, $force );
if (!$d2) {
fs_log("!!fail $d2");
return;
}
$d = dir( $d1 );
while ( false !== ( $entry = $d->read() ) ) {
if ( $entry != '.' && $entry != '..' )
copy_folder( "$d1/$entry", "$d2/$entry", $upd, $force );
}
$d->close();
}
else {
$ok = copy_safe( $d1, $d2, $upd );
$ok = ($ok) ? "ok-- " : " -- ";
fs_log("{$ok}$d1");
}
} //function copy_folder
function mkdir_safe( $dir, $force ) {
if (file_exists($dir)) {
if (is_dir($dir)) return $dir;
else if (!$force) return false;
unlink($dir);
}
return (mkdir($dir, 0777, true)) ? $dir : false;
} //function mkdir_safe
function copy_safe ($f1, $f2, $upd) {
$time1 = filemtime($f1);
if (file_exists($f2)) {
$time2 = filemtime($f2);
if ($time2 >= $time1 && $upd) return false;
}
$ok = copy($f1, $f2);
if ($ok) touch($f2, $time1);
return $ok;
} //function copy_safe
function fs_log($str) {
return;
$log = fopen("./fs_log.txt", "a");
$time = date("Y-m-d H:i:s");
fwrite($log, "$str ($time)\n");
fclose($log);
} }
try {
$sourcePath = __DIR__;
$targetPath = realpath($argv[1]);
echo $newEntity->getId() . PHP_EOL; if ($targetPath === false) {
throw new InvalidArgumentException("Invalid target path: {$argv[1]}");
}
$targetEntity = __getModuleEntity($targetPath);
$sourceEntity = __getModuleEntity($sourcePath);
copy_folder($nullEntity->getDir(), $newEntity->getDir()); echo "Cloning {$sourceEntity->getId()} -> {$targetEntity->getId()}..." . PHP_EOL;
$cloner = new ModuleCloner($sourceEntity, $targetEntity);
$cloner->clone();
echo "Success: Module cloned successfully." . PHP_EOL;
} catch (Throwable $e) {
echo "Critical Error: " . $e->getMessage() . PHP_EOL;
exit(1);
}
+122
View File
@@ -0,0 +1,122 @@
<?php
use Wt\Core\App\ModuleEntity;
require './../wt.core/include.php';
$curPath = __DIR__;
$newPath = realpath($argv[1]);
$newEntity = __getModuleEntity($newPath);
$nullableEntity = __getModuleEntity(__DIR__);
function copy_folder_safe($d1, $d2, $upd = true, $force = true, $exclude = [], $handler = null) {
$cm = 0;
preg_filter($exclude, $exclude, $d1, -1, $cm);
if($cm){
echo 'skip ' . $d1 . PHP_EOL;
return;
}
if(is_callable($handler)){
call_user_func_array($handler, [$d1, &$d2]);
}
if ( is_dir( $d1 ) ) {
$d2 = mkdir_safe( $d2, $force );
if (!$d2) {
return;
}
$d = dir( $d1 );
while ( false !== ( $entry = $d->read() ) ) {
if ( $entry != '.' && $entry != '..' )
copy_folder_safe( "$d1/$entry", "$d2/$entry", $upd, $force, $exclude, $handler);
}
$d->close();
}
else {
$ok = copy_safe( $d1, $d2, $upd );
}
}
function mkdir_safe( $dir, $force ) {
if (file_exists($dir)) {
if (is_dir($dir)) return $dir;
elseif (!$force) return false;
unlink($dir);
}
return (mkdir($dir, 0777, true)) ? $dir : false;
}
function copy_safe ($f1, $f2, $upd) {
$time1 = filemtime($f1);
if (file_exists($f2)) {
$time2 = filemtime($f2);
if ($time2 >= $time1 && $upd) return false;
}
$ok = copy($f1, $f2);
if ($ok) touch($f2, $time1);
return $ok;
}
function fs_log($str) {
return;
$log = fopen('./fs_log.txt', 'a');
$time = date('Y-m-d H:i:s');
fwrite($log, "$str ($time)\n");
fclose($log);
}
function _fix(ModuleEntity $newEntity, ModuleEntity $nullableEntity){
$d = new RecursiveDirectoryIterator( $newEntity->getPath() );
foreach( new RecursiveIteratorIterator( $d, 1 ) as $path ){
if( is_file( $path ) && str_ends_with($path, '.php')){
$orig_file = file_get_contents($path);
$new_file = $orig_file;
$cr = 0;
$new_file = str_replace($nullableEntity->getLangPrefix(), $newEntity->getLangPrefix(), $new_file, $cr);
$new_file = str_replace($nullableEntity->getId(), $newEntity->getId(), $new_file, $cr);
$new_file = str_replace($nullableEntity->getPrefix(), $newEntity->getPrefix(), $new_file, $cr);
$new_file = str_replace($nullableEntity->getNamespace(), $newEntity->getNamespace(), $new_file, $cr);
$new_file = str_replace(
ucfirst($nullableEntity->getProductCode()) . ': ' . ucfirst($nullableEntity->getProductCode()),
ucfirst($newEntity->getProductCode()) . ': ' . ucfirst($newEntity->getProductCode()),
$new_file,
$cr
);
$new_file = str_replace(ucfirst($nullableEntity->getProductCode()), ucfirst($newEntity->getProductCode()), $new_file, $cr);
$new_file = str_replace(ucfirst($nullableEntity->getCompanyCode()), ucfirst($newEntity->getCompanyCode()), $new_file, $cr);
$new_file = str_replace($nullableEntity->getProductCode(), $newEntity->getProductCode(), $new_file, $cr);
$new_file = str_replace($nullableEntity->getCompanyCode(), $newEntity->getCompanyCode(), $new_file, $cr);
echo $cr . ' ' .$path . PHP_EOL;
if($orig_file != $new_file){
file_put_contents($path, $new_file);
}
}
}
}
echo $newEntity->getId() . PHP_EOL;
copy_folder_safe($nullableEntity->getPath(), $newEntity->getPath(), true, true, [
'/\.git$/',
'/\.module\.json/',
'/clone\.php/',
'/readme\.md/',
'/src\/\.env$/',
'/src\/config\.php$/',
], function ($d1, &$d2) use ($nullableEntity, $newEntity){
$lastModuleName = collect(explode('.', $newEntity->fields()->id))->last();
$lastNullableModuleName = collect(explode('.', $nullableEntity->fields()->id))->last();
$d2 = str_replace(ucfirst($lastNullableModuleName), ucfirst($lastModuleName), $d2, $cr);
$d2 = str_replace(strtolower($lastNullableModuleName), strtolower($lastModuleName), $d2, $cr);
});
_fix($newEntity, $nullableEntity);
+15 -1
View File
@@ -2,6 +2,20 @@
return [ return [
'MainAbstractFactory' => [ 'MainAbstractFactory' => [
'Bx\Null\Factory\NullFactory' => ['cache' => ['hit'], 'is_collection_query' => true], 'Bx\Nullable\Factory\NullableFactory' => ['cache' => ['hit'], 'is_collection_query' => true],
],
'events' => [
'main:OnPageStart' => [
['Bx\Nullable\Handlers\Autoloader', 'onPageStart'],
],
'main:OnProlog' => [
['Bx\Nullable\Handlers\Autoloader', 'onProlog'],
],
'main:OnEpilog' => [
['Bx\Nullable\Handlers\Autoloader', 'onEpilog'],
],
'main:OnBeforeProlog' => [
['Bx\Nullable\Handlers\Autoloader', 'onBeforeProlog'],
],
], ],
]; ];
+3 -4
View File
@@ -1,12 +1,11 @@
<?php <?php
use Bx\Null\App\App; use Bx\Nullable\App\App;
/** /**
* @return App * @return App
* @throws null * @throws null
*/ */
function nullApp() { function nullableApp() {
$app = App::getInstance('bx.null'); return App::getInstance('bx.nullable');
return $app;
} }
+47 -24
View File
@@ -1,19 +1,20 @@
<? <?php
use Bitrix\Main\EventManager; use Bitrix\Main\EventManager;
use Bitrix\Main\Loader;
IncludeModuleLangFile(__FILE__); IncludeModuleLangFile(__FILE__);
class bx_null extends \CModule class bx_nullable extends \CModule
{ {
public $module = []; public $module = [];
var $MODULE_GROUP_RIGHTS = 'Y'; public $MODULE_GROUP_RIGHTS = 'Y';
function __construct() public function __construct()
{ {
$module = []; $module = [];
if(file_exists(__DIR__.'/../.module.json')){ if (file_exists(__DIR__ . '/../.module.json')) {
$module = json_decode(file_get_contents(__DIR__.'/../.module.json'), true); $module = json_decode(file_get_contents(__DIR__ . '/../.module.json'), true);
} }
$this->module = $module; $this->module = $module;
@@ -25,32 +26,32 @@ class bx_null extends \CModule
$langPrefix = $module['prefix']; $langPrefix = $module['prefix'];
$this->PARTNER_NAME = GetMessage("{$langPrefix}_partner_name"); $this->PARTNER_NAME = GetMessage("{$langPrefix}_partner_name");
$this->PARTNER_URI = GetMessage("{$langPrefix}_partner_uri"); $this->PARTNER_URI = GetMessage("{$langPrefix}_partner_uri");
$this->MODULE_NAME = GetMessage("{$langPrefix}_module_name"); $this->MODULE_NAME = GetMessage("{$langPrefix}_module_name");
$this->MODULE_DESCRIPTION = GetMessage("{$langPrefix}_module_description"); $this->MODULE_DESCRIPTION = GetMessage("{$langPrefix}_module_description");
} }
function DoInstall() public function DoInstall()
{ {
global $DOCUMENT_ROOT, $APPLICATION; global $APPLICATION;
if(is_array($this->module['deps'])){ if (is_array($this->module['deps'])) {
foreach ($this->module['deps'] as $moduleId){ foreach ($this->module['deps'] as $moduleId) {
if (!\Bitrix\Main\Loader::includeModule($moduleId)) { if (!Loader::includeModule($moduleId)) {
$APPLICATION->ThrowException("Module {$moduleId} not installed!"); $APPLICATION->ThrowException("Module {$moduleId} not installed!");
return false; return false;
} }
} }
} }
if (!CheckVersion(PHP_VERSION, "5.4.0")) { if (!(version_compare(PHP_VERSION, '8.0.0') >= 0)) {
$APPLICATION->ThrowException('Php version required more 5.4.0'); $APPLICATION->ThrowException('Php version required more 8.0.0');
return false; return false;
} }
RegisterModule($this->MODULE_ID); RegisterModule($this->MODULE_ID);
RegisterModuleDependences("main", "OnPageStart", $this->MODULE_ID); RegisterModuleDependences('main', 'OnPageStart', $this->MODULE_ID);
$this->InstallEvents(); $this->InstallEvents();
$this->InstallCatalogExport(); $this->InstallCatalogExport();
@@ -58,37 +59,59 @@ class bx_null extends \CModule
return true; return true;
} }
function DoUninstall() public function DoUninstall()
{ {
global $DOCUMENT_ROOT, $APPLICATION; global $APPLICATION;
UnRegisterModule($this->MODULE_ID); UnRegisterModule($this->MODULE_ID);
UnRegisterModuleDependences("main", "OnPageStart", $this->MODULE_ID, "", ""); UnRegisterModuleDependences('main', 'OnPageStart', $this->MODULE_ID, '', '');
$this->UnInstallEvents(); $this->UnInstallEvents();
$this->UnInstallCatalogExport(); $this->UnInstallCatalogExport();
return true; return true;
} }
function InstallCatalogExport() public function InstallCatalogExport()
{ {
if(is_dir(__DIR__."/catalog_export") && \Bitrix\Main\Loader::includeModule('catalog')){ if (is_dir(__DIR__ . '/catalog_export') && Loader::includeModule('catalog')) {
CopyDirFiles(__DIR__."/catalog_export", $_SERVER["DOCUMENT_ROOT"].CATALOG_PATH2EXPORTS, true, true); CopyDirFiles(__DIR__ . '/catalog_export', $_SERVER['DOCUMENT_ROOT'] . CATALOG_PATH2EXPORTS, true, true);
} }
return true; return true;
} }
function UnInstallCatalogExport() public function UnInstallCatalogExport()
{ {
return true; return true;
} }
function InstallEvents() public function InstallEvents()
{ {
if (class_exists('\Bitrix\Main\EventManager')) {
$eventManager = EventManager::getInstance();
// $eventManager->registerEventHandler(
// 'main',
// 'OnPageStart',
// $this->MODULE_ID,
// 'Bx\Nullable\Handler\Handler',
// 'exec',
// 100
// );
}
return true; return true;
} }
function UnInstallEvents() public function UnInstallEvents()
{ {
if (class_exists('\Bitrix\Main\EventManager')) {
$eventManager = \Bitrix\Main\EventManager::getInstance();
// $eventManager->unRegisterEventHandler(
// 'main',
// 'OnPageStart',
// $this->MODULE_ID,
// 'Bx\Nullable\Handler\Handler',
// 'exec'
// );
}
return true; return true;
} }
} }
+5 -5
View File
@@ -1,5 +1,5 @@
<? <?php
$MESS ['bx_null_partner_name'] = 'CoreLion'; $MESS ['bx_nullable_partner_name'] = 'CoreLion';
$MESS ['bx_null_partner_uri'] = 'https://corelion.ru/'; $MESS ['bx_nullable_partner_uri'] = 'https://corelion.ru/';
$MESS ['bx_null_module_name'] = 'Bx: Null'; $MESS ['bx_nullable_module_name'] = 'Bx: Nullable';
$MESS ['bx_null_module_description'] = 'Null module'; $MESS ['bx_nullable_module_description'] = 'Nullable module';
@@ -0,0 +1,18 @@
<?php
namespace Bx\Nullable\AbstractFactory;
use Wt\Core\AbstractFactory\AAbstractFactory;
use Bx\Nullable\Factory\NullableFactory;
class MainAbstractFactory extends AAbstractFactory
{
/**
* @return NullableFactory
*/
public function getNullableFactory()
{
return $this->getFactoryInstance(NullableFactory::class);
}
}
@@ -1,12 +1,10 @@
<?php <?php
namespace Bx\Nullable\Ajax;
namespace Bx\Null\Ajax;
use Wt\Core\Ajax\AAjaxHandler; use Wt\Core\Ajax\AAjaxHandler;
class BxNull extends AAjaxHandler class BxNullable extends AAjaxHandler
{ {
public function ajaxStart() public function ajaxStart()
{ {
@@ -15,7 +13,7 @@ class BxNull extends AAjaxHandler
public function test() public function test()
{ {
$this->getResponse()->addData(['method' => 'test', 'version' => nullApp()->module()->getVersion()]); $this->getResponse()->addData(['method' => 'test', 'version' => app()::getInstance('bx.nullable')->module()->getVersion()]);
return $this->getResponse(); return $this->getResponse();
} }
} }
+18 -9
View File
@@ -1,18 +1,18 @@
<?php <?php
namespace Bx\Nullable\App;
namespace Bx\Null\App; use Bx\Nullable\Facade\DefaultDefines;
use Bx\Nullable\Facade\Defines;
use Bx\Nullable\Facade\DefaultServiceFacade;
use Bx\Null\Facade\DefaultDefines; use Bx\Nullable\Facade\ServiceFacade;
use Bx\Null\Facade\Defines; use Bx\Nullable\Facade\DefaultFactoryFacade;
use Bx\Null\Facade\DefaultServiceFacade; use Bx\Nullable\Facade\FactoryFacade;
use Bx\Null\Facade\ServiceFacade;
use Bx\Null\Facade\DefaultFactoryFacade;
use Bx\Null\Facade\FactoryFacade;
class App extends \Wt\Core\App\App class App extends \Wt\Core\App\App
{ {
protected $includeFileToInitPhp;
/** /**
* @param string $factoryName * @param string $factoryName
* @return FactoryFacade | DefaultFactoryFacade * @return FactoryFacade | DefaultFactoryFacade
@@ -39,4 +39,13 @@ class App extends \Wt\Core\App\App
{ {
return parent::defines(); return parent::defines();
} }
public function isIncludeFileToInitPhp($value = null)
{
if(is_null($value)){
return $this->includeFileToInitPhp;
}
$this->includeFileToInitPhp = $value;
return $this;
}
} }
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace Bx\Nullable\Collection;
use Wt\Core\Collection\AEntityCollection;
use Bx\Nullable\Entity\NullableEntity;
class NullableCollection extends AEntityCollection
{
/**
* @param $xmlId
* @return NullableEntity
* @deprecated
*/
public function &getByXmlId($xmlId)
{
return parent::getByXmlId($xmlId);
}
/**
* @param $id
* @param null $default
* @return NullableEntity|null
*/
public function &get($id, $default = null)
{
return parent::get($id, $default);
}
/**
* @return NullableEntity
*/
public function &first(callable $callback = null, $default = null)
{
return parent::first($callback, $default);
}
/**
* @return NullableEntity
*/
public function &last()
{
return parent::last();
}
/**
* @return NullableEntity
*/
public function shift()
{
return parent::shift();
}
/**
* @return NullableEntity
*/
public function pop()
{
return parent::pop();
}
/**
* @return NullableCollection|NullableEntity[]
*/
public function filter($callback = null)
{
return parent::filter($callback);
}
/**
* @return NullableEntity[]
*/
public function all()
{
return parent::all();
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace Bx\Nullable\Entity;
use Bx\Nullable\IFields\NullableFields;
use Bx\Nullable\Factory\NullableFactory;
use Wt\Core\Entity\AEntity;
class NullableEntity extends AEntity
{
/**
* @return NullableFactory
*/
public function getFactory()
{
return parent::getFactory();
}
/**
* @return NullableFields
*/
public function fields()
{
return parent::fields();
}
}
@@ -1,8 +1,6 @@
<?php <?php
namespace Bx\Nullable\Facade;
namespace Bx\Null\Facade;
use Wt\Core\App\ADefines; use Wt\Core\App\ADefines;
@@ -1,10 +1,8 @@
<?php <?php
namespace Bx\Nullable\Facade;
namespace Bx\Null\Facade; use Bx\Nullable\AbstractFactory\MainAbstractFactory;
use Bx\Null\AbstractFactory\MainAbstractFactory;
use Wt\Core\Facade\AFacade; use Wt\Core\Facade\AFacade;
class DefaultFactoryFacade extends AFacade class DefaultFactoryFacade extends AFacade
@@ -1,8 +1,6 @@
<?php <?php
namespace Bx\Nullable\Facade;
namespace Bx\Null\Facade;
use Wt\Core\Facade\AFacade; use Wt\Core\Facade\AFacade;
@@ -1,44 +1,42 @@
<?php <?php
namespace Bx\Nullable\Factory;
namespace Bx\Null\Factory; use Bx\Nullable\Collection\NullableCollection;
use Bx\Nullable\Entity\NullableEntity;
use Bx\Nullable\ORM\NullableTable;
use Bx\Null\Collection\NullCollection;
use Bx\Null\Entity\NullEntity;
use Bx\Null\ORM\NullTable;
use Wt\Core\Factory\AFactory; use Wt\Core\Factory\AFactory;
use Wt\Core\Factory\AORMFactory; use Wt\Core\Factory\AORMFactory;
class NullFactory extends AORMFactory class NullableFactory extends AORMFactory
{ {
/** /**
* @return string|NullTable * @return string|NullableTable
*/ */
protected function __getDataManagerClass() protected function __getDataManagerClass()
{ {
return NullTable::class; return NullableTable::class;
} }
public function __getEntityClass() public function __getEntityClass()
{ {
return NullEntity::class; return NullableEntity::class;
} }
public function __getCachePrefix() public function __getCachePrefix()
{ {
return 'bx_null'; return 'bx_nullable';
} }
public function __getCollectionClass() public function __getCollectionClass()
{ {
return NullCollection::class; return NullableCollection::class;
} }
/** /**
* @param $id * @param $id
* @return NullEntity * @return NullableEntity
*/ */
public function getEntityById($id) public function getEntityById($id)
{ {
@@ -51,24 +49,24 @@ class NullFactory extends AORMFactory
* @param array $select * @param array $select
* @param null $limit * @param null $limit
* @param null $offset * @param null $offset
* @return NullCollection|NullEntity[] * @return NullableCollection|NullableEntity[]
*/ */
public function getCollection($filter = [], $order = [], $select = [], $limit = null, $offset = null) public function getCollection($filter = [], $order = [], $select = [], $limit = null, $offset = null)
{ {
return parent::getCollection($filter, $order, $select, $limit, $offset); // TODO: Change the autogenerated stub return parent::getCollection($filter, $order, $select, $limit, $offset);
} }
/** /**
* @param array $arIds * @param array $arIds
* @return NullCollection|NullEntity[] * @return NullableCollection|NullableEntity[]
*/ */
public function getEntityByIds(array $arIds) public function getEntityByIds(array $arIds)
{ {
return parent::getEntityByIds($arIds); // TODO: Change the autogenerated stub return parent::getEntityByIds($arIds);
} }
/** /**
* @return NullTable * @return NullableTable
*/ */
public function getDataManager() public function getDataManager()
{ {
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace Bx\Nullable\Handlers;
class Autoloader
{
public static function onPageStart(){}
public static function onBeforeProlog(){}
public static function onProlog(){}
public static function onEpilog(){}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace Bx\Nullable\IFields;
use Wt\Core\Interfaces\IFields;
class NullableFields implements IFields
{
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Bx\Nullable\Interfaces;
class ITest
{
}
@@ -1,39 +1,38 @@
<?php <?php
namespace Bx\Nullable\ORM;
namespace Bx\Null\ORM;
use Bitrix\Main\ORM\Fields\DatetimeField; use Bitrix\Main\ORM\Fields\DatetimeField;
use Bitrix\Main\Type\DateTime; use Bitrix\Main\Type\DateTime;
use Exception;
use Wt\Core\ORM\ADataManager; use Wt\Core\ORM\ADataManager;
class NullTable extends ADataManager class NullableTable extends ADataManager
{ {
public static function getTitle() public static function getTitle()
{ {
return 'Null Title'; return 'Nullable Title';
} }
public static function getRowTitle() public static function getRowTitle()
{ {
return 'Null Row Title'; return 'Nullable Row Title';
} }
public static function getRowDescription() public static function getRowDescription()
{ {
return 'Null Row Description'; return 'Nullable Row Description';
} }
public static function getTableName() public static function getTableName()
{ {
return 'bx_null_table'; return 'bx_nullable_table';
} }
public static function getMap() public static function getMap()
{ {
return array( return [
'ID' => new \Bitrix\Main\Entity\IntegerField('ID', [ 'ID' => new \Bitrix\Main\Entity\IntegerField('ID', [
'primary' => true, 'primary' => true,
'autocomplete' => true, 'autocomplete' => true,
@@ -47,39 +46,39 @@ class NullTable extends ADataManager
'title' => 'UpdatedAt', 'title' => 'UpdatedAt',
'user_edit' => false, 'user_edit' => false,
]), ]),
); ];
} }
/** /**
* @param $id * @param $primary
* @param array $fields * @param array $data
* @return \Bitrix\Main\ORM\Data\UpdateResult * @return \Bitrix\Main\ORM\Data\UpdateResult
* @throws \Bitrix\Main\ObjectException * @throws \Bitrix\Main\ObjectException
* @throws Exception
*/ */
public static function update($id, array $fields) public static function update($primary, array $data)
{ {
foreach (static::getEntity()->getFields() as $field){ foreach (static::getEntity()->getFields() as $field){
if(is_a($field, DatetimeField::class)){ if(is_a($field, DatetimeField::class)){
if(isset($fields[$field->getName()]) && !is_a($fields[$field->getName()], DateTime::class)) { if(isset($data[$field->getName()]) && !is_a($data[$field->getName()], DateTime::class)) {
$fields[$field->getName()] = new \Bitrix\Main\Type\DateTime($fields[$field->getName()]); $data[$field->getName()] = new \Bitrix\Main\Type\DateTime($data[$field->getName()]);
} }
} }
} }
$fields = array_merge($fields, [ $data = array_merge($data, [
'UPDATED_AT' => new \Bitrix\Main\Type\DateTime(), // date(CDatabase::DateFormatToPHP(FORMAT_DATETIME)) 'UPDATED_AT' => new \Bitrix\Main\Type\DateTime(), // date(CDatabase::DateFormatToPHP(FORMAT_DATETIME))
]); ]);
unset($fields['CREATED_AT']); unset($data['CREATED_AT']);
$result = parent::update($id, $fields); return parent::update($primary, $data);
return $result;
} }
/** /**
* @param array $fields * @param array $fields
* @return \Bitrix\Main\ORM\Data\AddResult * @return \Bitrix\Main\ORM\Data\AddResult
* @throws \Bitrix\Main\ObjectException * @throws \Bitrix\Main\ObjectException
* @throws Exception
*/ */
public static function add(array $fields) public static function add(array $fields)
{ {
@@ -88,7 +87,6 @@ class NullTable extends ADataManager
'UPDATED_AT' => new \Bitrix\Main\Type\DateTime(), 'UPDATED_AT' => new \Bitrix\Main\Type\DateTime(),
]); ]);
$result = parent::add($fields); return parent::add($fields);
return $result;
} }
} }
@@ -1,10 +1,8 @@
<?php <?php
namespace Bx\Nullable\Providers;
namespace Bx\Null\Providers; use Bx\Nullable\AbstractFactory\MainAbstractFactory;
use Bx\Null\AbstractFactory\MainAbstractFactory;
use Wt\Core\Interfaces\IApp; use Wt\Core\Interfaces\IApp;
use Wt\Core\Interfaces\IServiceProvider; use Wt\Core\Interfaces\IServiceProvider;
@@ -16,7 +14,7 @@ class DefaultFactoryProvider implements IServiceProvider
$serviceContainer = $app->container(); $serviceContainer = $app->container();
/** /**
* @var $mainAbstractFactory MainAbstractFactory * @var MainAbstractFactory $mainAbstractFactory
*/ */
$mainAbstractFactory = $serviceContainer->make(MainAbstractFactory::class, [$config->get('MainAbstractFactory', [])]); $mainAbstractFactory = $serviceContainer->make(MainAbstractFactory::class, [$config->get('MainAbstractFactory', [])]);
$serviceContainer->singleton($app->module()->getId().':mainAbstractFactory', $mainAbstractFactory); $serviceContainer->singleton($app->module()->getId().':mainAbstractFactory', $mainAbstractFactory);
@@ -1,8 +1,6 @@
<?php <?php
namespace Bx\Nullable\Providers;
namespace Bx\Null\Providers;
use Wt\Core\Interfaces\IApp; use Wt\Core\Interfaces\IApp;
use Wt\Core\Providers\ADefaultServiceProvider; use Wt\Core\Providers\ADefaultServiceProvider;
@@ -1,20 +0,0 @@
<?php
namespace Bx\Null\AbstractFactory;
use Wt\Core\AbstractFactory\AAbstractFactory;
use Bx\Null\Factory\NullFactory;
class MainAbstractFactory extends AAbstractFactory
{
/**
* @return NullFactory
*/
public function getNullFactory()
{
return $this->getFactoryInstance(NullFactory::class);
}
}
-71
View File
@@ -1,71 +0,0 @@
<?php
namespace Bx\Null\Collection;
use Wt\Core\Collection\AEntityCollection;
use Bx\Null\Entity\NullEntity;
class NullCollection extends AEntityCollection
{
/**
* @param $xmlId
* @return NullEntity
*/
public function &getByXmlId($xmlId)
{
return parent::getByXmlId($xmlId);
}
/**
* @param $id
* @param null $default
* @return NullEntity|null
*/
public function &get($id, $default = null)
{
return parent::get($id, $default); // TODO: Change the autogenerated stub
}
/**
* @return NullEntity
*/
public function &first()
{
return parent::first(); // TODO: Change the autogenerated stub
}
/**
* @return NullEntity
*/
public function &last()
{
return parent::last(); // TODO: Change the autogenerated stub
}
/**
* @return NullEntity
*/
public function shift()
{
return parent::shift(); // TODO: Change the autogenerated stub
}
/**
* @return NullEntity
*/
public function pop()
{
return parent::pop(); // TODO: Change the autogenerated stub
}
/**
* @return NullEntity[]
*/
public function all()
{
return parent::all(); // TODO: Change the autogenerated stub
}
}
-20
View File
@@ -1,20 +0,0 @@
<?php
namespace Bx\Null\Entity;
use Bx\Null\IFields\NullFields;
use Wt\Core\Entity\AEntity;
use Wt\Core\Supports\Entity;
class NullEntity extends AEntity
{
/**
* @return NullFields
*/
public function fields()
{
return parent::fields();
}
}
-12
View File
@@ -1,12 +0,0 @@
<?php
namespace Bx\Null\IFields;
use Wt\Core\Interfaces\IFields;
class NullFields implements IFields
{
}
+3
View File
@@ -0,0 +1,3 @@
1) создаем папку с модулем
2) копируем и конфигурируем файл .module.json
3) запускаем php -f clone.php ../path_to_new_module
+1
View File
@@ -0,0 +1 @@
local
+7
View File
@@ -0,0 +1,7 @@
<?php
/**
* @var array $config
*/
return [
'providers' => [],
];