dolibarr 21.0.0-alpha
index.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2023 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2018-2019 Nicolas ZABOURI <info@inovea-conseil.com>
4 * Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 *
21 * You can also make a direct call the page with parameter like this:
22 * htdocs/modulebuilder/index.php?module=Inventory@/pathtodolibarr/htdocs/product
23 */
24
33if (!defined('NOSCANPOSTFORINJECTION')) {
34 define('NOSCANPOSTFORINJECTION', '1'); // Do not check anti SQL+XSS injection attack test
35}
36
37// Load Dolibarr environment
38require '../main.inc.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/modulebuilder.lib.php';
43require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
44require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
45
46// Load translation files required by the page
47$langs->loadLangs(array("admin", "modulebuilder", "exports", "other", "cron", "errors"));
48
49// GET Parameters
50$action = GETPOST('action', 'aZ09');
51$confirm = GETPOST('confirm', 'alpha');
52$cancel = GETPOST('cancel', 'alpha');
53
54$sortfield = GETPOST('sortfield', 'alpha');
55$sortorder = GETPOST('sortorder', 'aZ09');
56
57$module = GETPOST('module', 'alpha');
58$tab = GETPOST('tab', 'aZ09');
59$tabobj = GETPOST('tabobj', 'alpha');
60$tabdic = GETPOST('tabdic', 'alpha');
61$propertykey = GETPOST('propertykey', 'alpha');
62if (empty($module)) {
63 $module = 'initmodule';
64}
65if (empty($tab)) {
66 $tab = 'description';
67}
68if (empty($tabobj)) {
69 $tabobj = 'newobjectifnoobj';
70}
71if (empty($tabdic)) {
72 $tabdic = 'newdicifnodic';
73}
74$file = GETPOST('file', 'alpha');
75$find = GETPOST('find', 'alpha');
76
77$modulename = dol_sanitizeFileName(GETPOST('modulename', 'alpha'));
78$objectname = dol_sanitizeFileName(GETPOST('objectname', 'alpha'));
79$dicname = dol_sanitizeFileName(GETPOST('dicname', 'alpha'));
80$editorname = GETPOST('editorname', 'alpha');
81$editorurl = GETPOST('editorurl', 'alpha');
82$version = GETPOST('version', 'alpha');
83$family = GETPOST('family', 'alpha');
84$picto = GETPOST('idpicto', 'alpha');
85$idmodule = GETPOST('idmodule', 'alpha');
86$format = ''; // Prevent undefined in css tab
87
88// Security check
89if (!isModEnabled('modulebuilder')) {
90 accessforbidden('Module ModuleBuilder not enabled');
91}
92if (!$user->hasRight("modulebuilder", "run")) {
93 accessforbidden('ModuleBuilderNotAllowed');
94}
95
96// Dir for custom dirs
97$tmp = explode(',', $dolibarr_main_document_root_alt);
98$dirins = $tmp[0];
99$dirread = $dirins;
100$forceddirread = 0;
101
102$tmpdir = explode('@', $module);
103if (!empty($tmpdir[1])) {
104 $module = $tmpdir[0];
105 $dirread = $tmpdir[1];
106 $forceddirread = 1;
107}
108if (GETPOST('dirins', 'alpha')) {
109 $dirread = $dirins = GETPOST('dirins', 'alpha');
110 $forceddirread = 1;
111}
112
113$FILEFLAG = 'modulebuilder.txt';
114
115$now = dol_now();
116$newmask = 0;
117if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
118 $newmask = getDolGlobalString('MAIN_UMASK');
119}
120if (empty($newmask)) { // This should no happen
121 $newmask = '0664';
122}
123
124$result = restrictedArea($user, 'modulebuilder', 0);
125
126$error = 0;
127
128$form = new Form($db);
129
130// Define $listofmodules
131$dirsrootforscan = array($dirread);
132
133// Add also the core modules into the list of modules to show/edit
134if ($dirread != DOL_DOCUMENT_ROOT && (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2 || getDolGlobalString('MODULEBUILDER_ADD_DOCUMENT_ROOT'))) {
135 $dirsrootforscan[] = DOL_DOCUMENT_ROOT;
136}
137
138// Search modules to edit
139$textforlistofdirs = '<!-- Directory scanned -->'."\n";
140$listofmodules = array();
141$i = 0;
142foreach ($dirsrootforscan as $tmpdirread) {
143 $moduletype = 'external';
144 if ($tmpdirread == DOL_DOCUMENT_ROOT) {
145 $moduletype = 'internal';
146 }
147
148 $dirsincustom = dol_dir_list($tmpdirread, 'directories');
149 if (is_array($dirsincustom) && count($dirsincustom) > 0) {
150 foreach ($dirsincustom as $dircustomcursor) {
151 $fullname = $dircustomcursor['fullname'];
152 if (dol_is_file($fullname.'/'.$FILEFLAG)) {
153 // Get real name of module (MyModule instead of mymodule)
154 $dirtoscanrel = basename($fullname).'/core/modules/';
155
156 $descriptorfiles = dol_dir_list(dirname($fullname).'/'.$dirtoscanrel, 'files', 0, 'mod.*\.class\.php$');
157 if (empty($descriptorfiles)) { // If descriptor not found into module dir, we look into main module dir.
158 $dirtoscanrel = 'core/modules/';
159 $descriptorfiles = dol_dir_list($fullname.'/../'.$dirtoscanrel, 'files', 0, 'mod'.strtoupper(basename($fullname)).'\.class\.php$');
160 }
161 $modulenamewithcase = '';
162 $moduledescriptorrelpath = '';
163 $moduledescriptorfullpath = '';
164
165 foreach ($descriptorfiles as $descriptorcursor) {
166 $modulenamewithcase = preg_replace('/^mod/', '', $descriptorcursor['name']);
167 $modulenamewithcase = preg_replace('/\.class\.php$/', '', $modulenamewithcase);
168 $moduledescriptorrelpath = $dirtoscanrel.$descriptorcursor['name'];
169 $moduledescriptorfullpath = $descriptorcursor['fullname'];
170 //var_dump($descriptorcursor);
171 }
172 if ($modulenamewithcase) {
173 $listofmodules[$dircustomcursor['name']] = array(
174 'modulenamewithcase' => $modulenamewithcase,
175 'moduledescriptorrelpath' => $moduledescriptorrelpath,
176 'moduledescriptorfullpath' => $moduledescriptorfullpath,
177 'moduledescriptorrootpath' => $tmpdirread,
178 'moduletype' => $moduletype
179 );
180 }
181 //var_dump($listofmodules);
182 }
183 }
184 }
185
186 if ($forceddirread && empty($listofmodules)) { // $forceddirread is 1 if we forced dir to read with dirins=... or with module=...@mydir
187 $listofmodules[strtolower($module)] = array(
188 'modulenamewithcase' => $module,
189 'moduledescriptorrelpath' => 'notyetimplemented',
190 'moduledescriptorfullpath' => 'notyetimplemented',
191 'moduledescriptorrootpath' => 'notyetimplemented',
192 );
193 }
194
195 // Show description of content
196 $newdircustom = $dirins;
197 if (empty($newdircustom)) {
198 $newdircustom = img_warning();
199 }
200 // If dirread was forced to somewhere else, by using URL
201 // htdocs/modulebuilder/index.php?module=Inventory@/home/ldestailleur/git/dolibarr/htdocs/product
202 if (empty($i)) {
203 $textforlistofdirs .= $langs->trans("DirScanned").' : ';
204 } else {
205 $textforlistofdirs .= ', ';
206 }
207 $textforlistofdirs .= '<strong class="wordbreakimp">'.$tmpdirread.'</strong>';
208 if ($tmpdirread == DOL_DOCUMENT_ROOT) {
209 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
210 $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MAIN_FEATURES_LEVEL"));
211 }
212 if (getDolGlobalString('MODULEBUILDER_ADD_DOCUMENT_ROOT')) {
213 $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MODULEBUILDER_ADD_DOCUMENT_ROOT"));
214 }
215 }
216 $i++;
217}
218
225{
226 $error = error_get_last();
227 if ($error && ($error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR))) {
228 // Handle the fatal error
229 echo "Fatal error occurred: {$error['message']} in {$error['file']} on line {$error['line']}";
230 // If a header was already send, we suppose it is the llx_Header() so we call the llxFooter()
231 if (headers_sent()) {
232 llxFooter();
233 }
234 }
235}
236register_shutdown_function("moduleBuilderShutdownFunction");
237
238
248function getLicenceHeader($user, $langs, $now)
249{
250 $licInfo = $user->getFullName($langs);
251 $emailTabs = str_repeat("\t", (int) (max(0, (31 - mb_strlen($licInfo)) / 4)));
252 $licInfo .= ($user->email ? $emailTabs.'<'.$user->email.'>' : '');
253 $licInfo = dol_print_date($now, '%Y')."\t\t".$licInfo;
254 return $licInfo;
255}
256
257/*
258 * Actions
259 */
260
261if ($dirins && $action == 'initmodule' && $modulename && $user->hasRight("modulebuilder", "run")) {
262 $modulename = ucfirst($modulename); // Force first letter in uppercase
263 $destdir = '/not_set/';
264
265 if (preg_match('/[^a-z0-9_]/i', $modulename)) {
266 $error++;
267 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
268 }
269
270 if (!$error) {
271 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
272 $destdir = $dirins.'/'.strtolower($modulename);
273
274 $arrayreplacement = array(
275 'mymodule' => strtolower($modulename),
276 'MyModule' => $modulename
277 );
278 $result = dolCopyDir($srcdir, $destdir, '0', 0, $arrayreplacement);
279 //dol_mkdir($destfile);
280 if ($result <= 0) {
281 if ($result < 0) {
282 $error++;
283 $langs->load("errors");
284 setEventMessages($langs->trans("ErrorFailToCopyDir", $srcdir, $destdir), null, 'errors');
285 } else {
286 // $result == 0
287 setEventMessages($langs->trans("AllFilesDidAlreadyExist", $srcdir, $destdir), null, 'warnings');
288 }
289 }
290
291 // Copy last 'html.formsetup.class.php' to backport folder
292 if (getDolGlobalInt('MODULEBUILDER_SUPPORT_COMPATIBILITY_V16')) {
293 $tryToCopyFromSetupClass = true;
294 $backportDest = $destdir .'/backport/v16/core/class';
295 $backportFileSrc = DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
296 $backportFileDest = $backportDest.'/html.formsetup.class.php';
297 $result = dol_mkdir($backportDest);
298
299 if ($result < 0) {
300 $error++;
301 $langs->load("errors");
302 setEventMessages($langs->trans("ErrorFailToCreateDir", $backportDest), null, 'errors');
303 $tryToCopyFromSetupClass = false;
304 }
305
306 if ($tryToCopyFromSetupClass) {
307 $result = dol_copy($backportFileSrc, $backportFileDest);
308 if ($result <= 0) {
309 if ($result < 0) {
310 $error++;
311 $langs->load("errors");
312 setEventMessages($langs->trans("ErrorFailToCopyFile", $backportFileSrc, $backportFileDest), null, 'errors');
313 } else {
314 setEventMessages($langs->trans("FileDidAlreadyExist", $backportFileDest), null, 'warnings');
315 }
316 }
317 }
318 }
319
320 if (getDolGlobalString('MODULEBUILDER_USE_ABOUT')) {
321 dol_delete_file($destdir.'/admin/about.php');
322 }
323
324 // Delete dir and files that can be generated in sub tabs later if we need them (we want a minimal module first)
325 dol_delete_dir_recursive($destdir.'/ajax');
326 dol_delete_dir_recursive($destdir.'/build/doxygen');
327 dol_delete_dir_recursive($destdir.'/core/modules/mailings');
328 dol_delete_dir_recursive($destdir.'/core/modules/'.strtolower($modulename));
329 dol_delete_dir_recursive($destdir.'/core/tpl');
330 dol_delete_dir_recursive($destdir.'/core/triggers');
331 dol_delete_dir_recursive($destdir.'/doc');
332 //dol_delete_dir_recursive($destdir.'/.tx');
333 dol_delete_dir_recursive($destdir.'/core/boxes');
334
335 dol_delete_file($destdir.'/admin/myobject_extrafields.php');
336
337 dol_delete_file($destdir.'/class/actions_'.strtolower($modulename).'.class.php');
338 dol_delete_file($destdir.'/class/api_'.strtolower($modulename).'.class.php');
339
340 dol_delete_file($destdir.'/css/'.strtolower($modulename).'.css.php');
341
342 dol_delete_file($destdir.'/js/'.strtolower($modulename).'.js.php');
343
344 dol_delete_file($destdir.'/scripts/'.strtolower($modulename).'.php');
345
346 dol_delete_file($destdir.'/sql/data.sql');
347 dol_delete_file($destdir.'/sql/update_x.x.x-y.y.y.sql');
348
349 // Delete some files related to Object (because the previous dolCopyDir has copied everything)
350 dol_delete_file($destdir.'/myobject_card.php');
351 dol_delete_file($destdir.'/myobject_contact.php');
352 dol_delete_file($destdir.'/myobject_note.php');
353 dol_delete_file($destdir.'/myobject_document.php');
354 dol_delete_file($destdir.'/myobject_agenda.php');
355 dol_delete_file($destdir.'/myobject_list.php');
356 dol_delete_file($destdir.'/lib/'.strtolower($modulename).'_myobject.lib.php');
357 dol_delete_file($destdir.'/test/phpunit/functional/'.$modulename.'FunctionalTest.php');
358 dol_delete_file($destdir.'/test/phpunit/MyObjectTest.php');
359 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.sql');
360 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.sql');
361 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.key.sql');
362 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.key.sql');
363 dol_delete_file($destdir.'/class/myobject.class.php');
364
365 dol_delete_dir($destdir.'/class', 1);
366 dol_delete_dir($destdir.'/css', 1);
367 dol_delete_dir($destdir.'/js', 1);
368 dol_delete_dir($destdir.'/scripts', 1);
369 dol_delete_dir($destdir.'/sql', 1);
370 dol_delete_dir($destdir.'/test/phpunit/functionnal', 1);
371 dol_delete_dir($destdir.'/test/phpunit', 1);
372 dol_delete_dir($destdir.'/test', 1);
373 }
374
375 // Edit PHP files
376 if (!$error) {
377 $listofphpfilestoedit = dol_dir_list($destdir, 'files', 1, '\.(php|MD|js|sql|txt|xml|lang)$', '', 'fullname', SORT_ASC, 0, 1);
378
379 $licInfo = getLicenceHeader($user, $langs, $now);
380 foreach ($listofphpfilestoedit as $phpfileval) {
381 //var_dump($phpfileval['fullname']);
382 $arrayreplacement = array(
383 'mymodule' => strtolower($modulename),
384 'MyModule' => $modulename,
385 'MYMODULE' => strtoupper($modulename),
386 'My module' => $modulename,
387 'my module' => $modulename,
388 'Mon module' => $modulename,
389 'mon module' => $modulename,
390 'htdocs/modulebuilder/template' => strtolower($modulename),
391 '---Put here your own copyright and developer email---' => $licInfo,
392 '---Replace with your own copyright and developer email---' => $licInfo,
393 'Editor name' => $editorname,
394 'https://www.example.com' => $editorurl,
395 '$this->version = \'1.0\'' => '$this->version = \''.$version.'\'',
396 '$this->picto = \'generic\';' => (empty($picto)) ? '$this->picto = \'generic\'' : '$this->picto = \''.$picto.'\';',
397 "modulefamily" => $family,
398 '500000' => $idmodule
399 );
400
401 if (getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')) {
402 $arrayreplacement['---Replace with your own copyright and developer email---'] = dol_print_date($now, '%Y')."\t\t" . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR');
403 }
404
405 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
406 $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement);
407 //var_dump($result);
408 if ($result < 0) {
409 setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
410 }
411 }
412
413 if (getDolGlobalString('MODULEBUILDER_SPECIFIC_README')) {
414 setEventMessages($langs->trans("ContentOfREADMECustomized"), null, 'warnings');
415 dol_delete_file($destdir.'/README.md');
416 file_put_contents($destdir.'/README.md', $conf->global->MODULEBUILDER_SPECIFIC_README);
417 }
418 // for create file to add properties
419 // file_put_contents($destdir.'/'.strtolower($modulename).'propertycard.php','');
420 // $srcFileCard = DOL_DOCUMENT_ROOT.'/modulebuilder/card.php';
421 // $destFileCard = $dirins.'/'.strtolower($modulename).'/template/card.php';
422 // dol_copy($srcFileCard, $destdir.'/'.strtolower($modulename).'propertycard.php', '0',1, $arrayreplacement);
423 }
424
425 if (!$error) {
426 setEventMessages('ModuleInitialized', null);
427 $module = $modulename;
428
429 clearstatcache(true);
430 if (function_exists('opcache_invalidate')) {
431 opcache_reset(); // remove the include cache hell !
432 }
433
434 header("Location: ".$_SERVER["PHP_SELF"].'?module='.$modulename);
435 exit;
436 }
437}
438
439$destdir = '/not_set/'; // Initialize (for static analysis)
440$destfile = '/not_set/'; // Initialize (for static analysis)
441$srcfile = '/not_set/'; // Initialize (for static analysis)
442
443// init API, PHPUnit
444if ($dirins && in_array($action, array('initapi', 'initphpunit', 'initpagecontact', 'initpagedocument', 'initpagenote', 'initpageagenda')) && !empty($module) && $user->hasRight("modulebuilder", "run")) {
445 $modulename = ucfirst($module); // Force first letter in uppercase
446 $objectname = $tabobj;
447 $varnametoupdate = '';
448 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
449 $destdir = $dirins.'/'.strtolower($module);
450
451 // Get list of existing objects
452 $objects = dolGetListOfObjectClasses($destdir);
453
454
455 if ($action == 'initapi') { // Test on permission already done
456 if (file_exists($dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php')) {
457 $result = dol_copy(DOL_DOCUMENT_ROOT.'/modulebuilder/template/class/api_mymodule.class.php', $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php', '0', 1);
458 }
459 dol_mkdir($dirins.'/'.strtolower($module).'/class');
460 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
461 $srcfile = $srcdir.'/class/api_mymodule.class.php';
462 $destfile = $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php';
463 } elseif ($action == 'initphpunit') { // Test on permission already done
464 dol_mkdir($dirins.'/'.strtolower($module).'/test/phpunit');
465 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
466 $srcfile = $srcdir.'/test/phpunit/MyObjectTest.php';
467 $destfile = $dirins.'/'.strtolower($module).'/test/phpunit/'.strtolower($objectname).'Test.php';
468 } elseif ($action == 'initpagecontact') { // Test on permission already done
469 dol_mkdir($dirins.'/'.strtolower($module));
470 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
471 $srcfile = $srcdir.'/myobject_contact.php';
472 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_contact.php';
473 $varnametoupdate = 'showtabofpagecontact';
474 } elseif ($action == 'initpagedocument') { // Test on permission already done
475 dol_mkdir($dirins.'/'.strtolower($module));
476 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
477 $srcfile = $srcdir.'/myobject_document.php';
478 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_document.php';
479 $varnametoupdate = 'showtabofpagedocument';
480 } elseif ($action == 'initpagenote') { // Test on permission already done
481 dol_mkdir($dirins.'/'.strtolower($module));
482 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
483 $srcfile = $srcdir.'/myobject_note.php';
484 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_note.php';
485 $varnametoupdate = 'showtabofpagenote';
486 } elseif ($action == 'initpageagenda') { // Test on permission already done
487 dol_mkdir($dirins.'/'.strtolower($module));
488 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
489 $srcfile = $srcdir.'/myobject_agenda.php';
490 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_agenda.php';
491 $varnametoupdate = 'showtabofpageagenda';
492 }
493
494 if (!file_exists($destfile)) {
495 $result = dol_copy($srcfile, $destfile, '0', 0);
496 }
497
498 if ($result > 0) {
499 //var_dump($phpfileval['fullname']);
500 $arrayreplacement = array(
501 'mymodule' => strtolower($modulename),
502 'MyModule' => $modulename,
503 'MYMODULE' => strtoupper($modulename),
504 'My module' => $modulename,
505 'my module' => $modulename,
506 'Mon module' => $modulename,
507 'mon module' => $modulename,
508 'htdocs/modulebuilder/template' => strtolower($modulename),
509 'myobject' => strtolower($objectname),
510 'MyObject' => $objectname,
511 'MYOBJECT' => strtoupper($objectname),
512
513 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
514 );
515
516 if ($action == 'initapi') { // Test on permission already done
517 if (count($objects) >= 1) {
518 addObjectsToApiFile($srcfile, $destfile, $objects, $modulename);
519 }
520 } else {
521 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
522 dolReplaceInFile($destfile, $arrayreplacement);
523 }
524
525 if ($varnametoupdate) {
526 // Now we update the object file to set $$varnametoupdate to 1
527 $srcfile = $dirins.'/'.strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php';
528 $arrayreplacement = array('/\$'.preg_quote($varnametoupdate, '/').' = 0;/' => '$'.$varnametoupdate.' = 1;');
529 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
530 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
531 }
532 } else {
533 $langs->load("errors");
534 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
535 }
536}
537
538
539// init ExtraFields
540if ($dirins && $action == 'initsqlextrafields' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
541 $modulename = ucfirst($module); // Force first letter in uppercase
542 $objectname = $tabobj;
543
544 dol_mkdir($dirins.'/'.strtolower($module).'/sql');
545 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
546 $srcfile1 = $srcdir.'/sql/llx_mymodule_myobject_extrafields.sql';
547 $destfile1 = $dirins.'/'.strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql';
548 $result1 = dol_copy($srcfile1, $destfile1, '0', 0);
549 $srcfile2 = $srcdir.'/sql/llx_mymodule_myobject_extrafields.key.sql';
550 $destfile2 = $dirins.'/'.strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql';
551 $result2 = dol_copy($srcfile2, $destfile2, '0', 0);
552
553 if ($result1 > 0 && $result2 > 0) {
554 $modulename = ucfirst($module); // Force first letter in uppercase
555
556 //var_dump($phpfileval['fullname']);
557 $arrayreplacement = array(
558 'mymodule' => strtolower($modulename),
559 'MyModule' => $modulename,
560 'MYMODULE' => strtoupper($modulename),
561 'My module' => $modulename,
562 'my module' => $modulename,
563 'Mon module' => $modulename,
564 'mon module' => $modulename,
565 'htdocs/modulebuilder/template' => strtolower($modulename),
566 'My Object' => $objectname,
567 'MyObject' => $objectname,
568 'my object' => strtolower($objectname),
569 'myobject' => strtolower($objectname),
570 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
571 );
572
573 dolReplaceInFile($destfile1, $arrayreplacement);
574 dolReplaceInFile($destfile2, $arrayreplacement);
575 } else {
576 $langs->load("errors");
577 if ($result1 <= 0) {
578 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile1), null, 'errors');
579 }
580 if ($result2 <= 0) {
581 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile2), null, 'errors');
582 }
583 }
584
585 // Now we update the object file to set $this->isextrafieldmanaged to 1
586 $srcfile = $dirins.'/'.strtolower($module).'/class/'.strtolower($objectname).'.class.php';
587 $arrayreplacement = array('/\$this->isextrafieldmanaged = 0;/' => '$this->isextrafieldmanaged = 1;');
588 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
589}
590
591
592// init Hook
593if ($dirins && $action == 'inithook' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
594 dol_mkdir($dirins.'/'.strtolower($module).'/class');
595 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
596 $srcfile = $srcdir.'/class/actions_mymodule.class.php';
597 $destfile = $dirins.'/'.strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
598 $result = dol_copy($srcfile, $destfile, '0', 0);
599
600 if ($result > 0) {
601 $modulename = ucfirst($module); // Force first letter in uppercase
602
603 //var_dump($phpfileval['fullname']);
604 $arrayreplacement = array(
605 'mymodule' => strtolower($modulename),
606 'MyModule' => $modulename,
607 'MYMODULE' => strtoupper($modulename),
608 'My module' => $modulename,
609 'my module' => $modulename,
610 'Mon module' => $modulename,
611 'mon module' => $modulename,
612 'htdocs/modulebuilder/template' => strtolower($modulename),
613 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
614 );
615
616 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
617 dolReplaceInFile($destfile, $arrayreplacement);
618 } else {
619 $langs->load("errors");
620 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
621 }
622}
623
624
625// init Trigger
626if ($dirins && $action == 'inittrigger' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
627 dol_mkdir($dirins.'/'.strtolower($module).'/core/triggers');
628 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
629 $srcfile = $srcdir.'/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php';
630 $destfile = $dirins.'/'.strtolower($module).'/core/triggers/interface_99_mod'.$module.'_'.$module.'Triggers.class.php';
631 $result = dol_copy($srcfile, $destfile, '0', 0);
632
633 if ($result > 0) {
634 $modulename = ucfirst($module); // Force first letter in uppercase
635
636 //var_dump($phpfileval['fullname']);
637 $arrayreplacement = array(
638 'mymodule' => strtolower($modulename),
639 'MyModule' => $modulename,
640 'MYMODULE' => strtoupper($modulename),
641 'My module' => $modulename,
642 'my module' => $modulename,
643 'Mon module' => $modulename,
644 'mon module' => $modulename,
645 'htdocs/modulebuilder/template' => strtolower($modulename),
646 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
647 );
648
649 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
650 dolReplaceInFile($destfile, $arrayreplacement);
651 } else {
652 $langs->load("errors");
653 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
654 }
655}
656
657
658// init Widget
659if ($dirins && $action == 'initwidget' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
660 dol_mkdir($dirins.'/'.strtolower($module).'/core/boxes');
661 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
662 $srcfile = $srcdir.'/core/boxes/mymodulewidget1.php';
663 $destfile = $dirins.'/'.strtolower($module).'/core/boxes/'.strtolower($module).'widget1.php';
664 $result = dol_copy($srcfile, $destfile, '0', 0);
665
666 if ($result > 0) {
667 $modulename = ucfirst($module); // Force first letter in uppercase
668
669 //var_dump($phpfileval['fullname']);
670 $arrayreplacement = array(
671 'mymodule' => strtolower($modulename),
672 'MyModule' => $modulename,
673 'MYMODULE' => strtoupper($modulename),
674 'My module' => $modulename,
675 'my module' => $modulename,
676 'Mon module' => $modulename,
677 'mon module' => $modulename,
678 'htdocs/modulebuilder/template' => strtolower($modulename),
679 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
680 );
681
682 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
683 dolReplaceInFile($destfile, $arrayreplacement);
684 } else {
685 $langs->load("errors");
686 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
687 }
688}
689
690
691// init EmailSelector
692if ($dirins && $action == 'initemailing' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
693 dol_mkdir($dirins.'/'.strtolower($module).'/core/modules/mailings');
694 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
695 $srcfile = $srcdir.'/core/modules/mailings/mailing_mymodule_selector1.modules.php';
696 $destfile = $dirins.'/'.strtolower($module).'/core/modules/mailings/mailing_'.strtolower($module).'_selector1.modules.php';
697 $result = dol_copy($srcfile, $destfile, '0', 0);
698
699 if ($result > 0) {
700 $modulename = ucfirst($module); // Force first letter in uppercase
701
702 //var_dump($phpfileval['fullname']);
703 $arrayreplacement = array(
704 'mymodule' => strtolower($modulename),
705 'MyModule' => $modulename,
706 'MYMODULE' => strtoupper($modulename),
707 'My module' => $modulename,
708 'my module' => $modulename,
709 'Mon module' => $modulename,
710 'mon module' => $modulename,
711 'htdocs/modulebuilder/template' => strtolower($modulename),
712 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
713 );
714
715 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
716 dolReplaceInFile($destfile, $arrayreplacement);
717 } else {
718 $langs->load("errors");
719 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
720 }
721}
722
723
724// init CSS
725if ($dirins && $action == 'initcss' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
726 dol_mkdir($dirins.'/'.strtolower($module).'/css');
727 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
728 $srcfile = $srcdir.'/css/mymodule.css.php';
729 $destfile = $dirins.'/'.strtolower($module).'/css/'.strtolower($module).'.css.php';
730 $result = dol_copy($srcfile, $destfile, '0', 0);
731
732 if ($result > 0) {
733 $modulename = ucfirst($module); // Force first letter in uppercase
734
735 //var_dump($phpfileval['fullname']);
736 $arrayreplacement = array(
737 'mymodule' => strtolower($modulename),
738 'MyModule' => $modulename,
739 'MYMODULE' => strtoupper($modulename),
740 'My module' => $modulename,
741 'my module' => $modulename,
742 'Mon module' => $modulename,
743 'mon module' => $modulename,
744 'htdocs/modulebuilder/template' => strtolower($modulename),
745 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
746 );
747
748 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
749 dolReplaceInFile($destfile, $arrayreplacement);
750
751 // Update descriptor file to uncomment file
752 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
753 $arrayreplacement = array('/\/\/\s*\''.preg_quote('/'.strtolower($module).'/css/'.strtolower($module).'.css.php', '/').'\'/' => '\'/'.strtolower($module).'/css/'.strtolower($module).'.css.php\'');
754 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
755 } else {
756 $langs->load("errors");
757 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
758 }
759}
760
761
762// init JS
763if ($dirins && $action == 'initjs' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
764 dol_mkdir($dirins.'/'.strtolower($module).'/js');
765 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
766 $srcfile = $srcdir.'/js/mymodule.js.php';
767 $destfile = $dirins.'/'.strtolower($module).'/js/'.strtolower($module).'.js.php';
768 $result = dol_copy($srcfile, $destfile, '0', 0);
769
770 if ($result > 0) {
771 $modulename = ucfirst($module); // Force first letter in uppercase
772
773 //var_dump($phpfileval['fullname']);
774 $arrayreplacement = array(
775 'mymodule' => strtolower($modulename),
776 'MyModule' => $modulename,
777 'MYMODULE' => strtoupper($modulename),
778 'My module' => $modulename,
779 'my module' => $modulename,
780 'Mon module' => $modulename,
781 'mon module' => $modulename,
782 'htdocs/modulebuilder/template' => strtolower($modulename),
783 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
784 );
785
786 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
787 dolReplaceInFile($destfile, $arrayreplacement);
788
789 // Update descriptor file to uncomment file
790 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
791 $arrayreplacement = array('/\/\/\s*\''.preg_quote('/'.strtolower($module).'/js/'.strtolower($module).'.js.php', '/').'\'/' => '\'/'.strtolower($module).'/js/'.strtolower($module).'.js.php\'');
792 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
793 } else {
794 $langs->load("errors");
795 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
796 }
797}
798
799
800// init CLI
801if ($dirins && $action == 'initcli' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
802 dol_mkdir($dirins.'/'.strtolower($module).'/scripts');
803 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
804 $srcfile = $srcdir.'/scripts/mymodule.php';
805 $destfile = $dirins.'/'.strtolower($module).'/scripts/'.strtolower($module).'.php';
806 $result = dol_copy($srcfile, $destfile, '0', 0);
807
808 if ($result > 0) {
809 $modulename = ucfirst($module); // Force first letter in uppercase
810
811 //var_dump($phpfileval['fullname']);
812 $arrayreplacement = array(
813 'mymodule' => strtolower($modulename),
814 'MyModule' => $modulename,
815 'MYMODULE' => strtoupper($modulename),
816 'My module' => $modulename,
817 'my module' => $modulename,
818 'Mon module' => $modulename,
819 'mon module' => $modulename,
820 'htdocs/modulebuilder/template' => strtolower($modulename),
821 '__MYCOMPANY_NAME__' => $mysoc->name,
822 '__KEYWORDS__' => $modulename,
823 '__USER_FULLNAME__' => $user->getFullName($langs),
824 '__USER_EMAIL__' => $user->email,
825 '__YYYY-MM-DD__' => dol_print_date($now, 'dayrfc'),
826 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
827 );
828
829 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
830 dolReplaceInFile($destfile, $arrayreplacement);
831 } else {
832 $langs->load("errors");
833 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
834 }
835}
836
837
838$moduledescriptorfile = '/not_set/';
839
840// init Doc
841if ($dirins && $action == 'initdoc' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
842 dol_mkdir($dirins.'/'.strtolower($module).'/doc');
843 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
844 $srcfile = $srcdir.'/doc/Documentation.asciidoc';
845 $destfile = $dirins.'/'.strtolower($module).'/doc/Documentation.asciidoc';
846 $result = dol_copy($srcfile, $destfile, '0', 0);
847
848 if ($result > 0) {
849 $modulename = ucfirst($module); // Force first letter in uppercase
850 $modulelowercase = strtolower($module);
851
852 //var_dump($phpfileval['fullname']);
853 $arrayreplacement = array(
854 'mymodule' => strtolower($modulename),
855 'MyModule' => $modulename,
856 'MYMODULE' => strtoupper($modulename),
857 'My module' => $modulename,
858 'my module' => $modulename,
859 'Mon module' => $modulename,
860 'mon module' => $modulename,
861 'htdocs/modulebuilder/template' => strtolower($modulename),
862 '__MYCOMPANY_NAME__' => $mysoc->name,
863 '__KEYWORDS__' => $modulename,
864 '__USER_FULLNAME__' => $user->getFullName($langs),
865 '__USER_EMAIL__' => $user->email,
866 '__YYYY-MM-DD__' => dol_print_date($now, 'dayrfc'),
867 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
868 );
869
870 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
871 dolReplaceInFile($destfile, $arrayreplacement);
872
873 // add table of properties
874 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
875 $destdir = $dirins.'/'.strtolower($module);
876 $objects = dolGetListOfObjectClasses($destdir);
877 foreach ($objects as $path => $obj) {
878 writePropsInAsciiDoc($path, $obj, $destfile);
879 }
880
881 // add table of permissions
882 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
883 writePermsInAsciiDoc($moduledescriptorfile, $destfile);
884
885 // add api urls if file exist
886 if (file_exists($dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php')) {
887 $apiFile = $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php';
888 writeApiUrlsInDoc($apiFile, $destfile);
889 }
890
891 // add ChangeLog in Doc
892 if (file_exists($dirins.'/'.strtolower($module).'/ChangeLog.md')) {
893 $changeLog = $dirins.'/'.strtolower($module).'/ChangeLog.md';
894 $string = file_get_contents($changeLog);
895
896 $replace = explode("\n", $string);
897 $strreplace = array();
898 foreach ($replace as $line) {
899 if ($line === '') {
900 continue;
901 }
902 if (strpos($line, '##') !== false) {
903 $strreplace[$line] = str_replace('##', '', $line);
904 } else {
905 $strreplace[$line] = $line;
906 }
907 }
908 $stringLog = implode("\n", $strreplace);
909 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
910 dolReplaceInFile($destfile, array('//include::ChangeLog.md[]' => '','__CHANGELOG__' => $stringLog));
911 }
912
913 // Delete old documentation files
914 $FILENAMEDOC = $modulelowercase.'.html';
915 $FILENAMEDOCPDF = $modulelowercase.'.pdf';
916 $outputfiledoc = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOC;
917 $outputfiledocurl = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOC;
918 $outputfiledocpdf = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOCPDF;
919 $outputfiledocurlpdf = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOCPDF;
920
921 dol_delete_file($outputfiledoc, 0, 0, 0, null, false, 0);
922 dol_delete_file($outputfiledocpdf, 0, 0, 0, null, false, 0);
923 } else {
924 $langs->load("errors");
925 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
926 }
927}
928
929
930// add Language
931if ($dirins && $action == 'addlanguage' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
932 $newlangcode = GETPOST('newlangcode', 'aZ09');
933
934 if ($newlangcode) {
935 $modulelowercase = strtolower($module);
936
937 // Dir for module
938 $diroflang = dol_buildpath($modulelowercase, 0);
939
940 if ($diroflang == $dolibarr_main_document_root.'/'.$modulelowercase) {
941 // This is not a custom module, we force diroflang to htdocs root
942 $diroflang = $dolibarr_main_document_root;
943
944 $srcfile = $diroflang.'/langs/en_US/'.$modulelowercase.'.lang';
945 $destfile = $diroflang.'/langs/'.$newlangcode.'/'.$modulelowercase.'.lang';
946
947 $result = dol_copy($srcfile, $destfile, '0', 0);
948 if ($result < 0) {
949 setEventMessages($langs->trans("ErrorFailToCopyFile", $srcfile, $destfile), null, 'errors');
950 }
951 } else {
952 $srcdir = $diroflang.'/langs/en_US';
953 $srcfile = $diroflang.'/langs/en_US/'.$modulelowercase.'.lang';
954 $destdir = $diroflang.'/langs/'.$newlangcode;
955
956 $arrayofreplacement = array();
957 if (!dol_is_dir($srcfile) || !dol_is_file($srcfile)) {
958 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template/langs/en_US';
959 $arrayofreplacement = array('mymodule' => $modulelowercase);
960 }
961 $result = dolCopyDir($srcdir, $destdir, '0', 0, $arrayofreplacement);
962 }
963 } else {
964 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Language")), null, 'errors');
965 }
966}
967
968
969// Remove/delete File
970if ($dirins && $action == 'confirm_removefile' && !empty($module) && $user->hasRight("modulebuilder", "run")) {
971 $objectname = $tabobj;
972 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
973 $destdir = $dirins.'/'.strtolower($module);
974
975 $relativefilename = dol_sanitizePathName(GETPOST('file', 'restricthtml'));
976
977 // Now we delete the file
978 if ($relativefilename) {
979 $dirnametodelete = dirname($relativefilename);
980 $filetodelete = $dirins.'/'.$relativefilename;
981 $dirtodelete = $dirins.'/'.$dirnametodelete;
982
983 // Get list of existing objects
984 $objects = dolGetListOfObjectClasses($destdir);
985
986 $keyofobjecttodelete = array_search($objectname, $objects);
987 if ($keyofobjecttodelete !== false) {
988 unset($objects[$keyofobjecttodelete]);
989 }
990
991 // Delete or modify the file
992 if (strpos($relativefilename, 'api') !== false) {
993 $file_api = $destdir.'/class/api_'.strtolower($module).'.class.php';
994
995 $removeFile = removeObjectFromApiFile($file_api, $objects, $objectname);
996
997 if (count($objects) == 0) {
998 $result = dol_delete_file($filetodelete);
999 }
1000
1001 if ($removeFile) {
1002 setEventMessages($langs->trans("ApiObjectDeleted"), null);
1003 }
1004 } else {
1005 $result = dol_delete_file($filetodelete);
1006 }
1007
1008 if (!$result) {
1009 setEventMessages($langs->trans("ErrorFailToDeleteFile", basename($filetodelete)), null, 'errors');
1010 } else {
1011 // If we delete a .sql file, we delete also the other .sql file
1012 if (preg_match('/\.sql$/', $relativefilename)) {
1013 if (preg_match('/\.key\.sql$/', $relativefilename)) {
1014 $relativefilename = preg_replace('/\.key\.sql$/', '.sql', $relativefilename);
1015 $filetodelete = $dirins.'/'.$relativefilename;
1016 $result = dol_delete_file($filetodelete);
1017 } elseif (preg_match('/\.sql$/', $relativefilename)) {
1018 $relativefilename = preg_replace('/\.sql$/', '.key.sql', $relativefilename);
1019 $filetodelete = $dirins.'/'.$relativefilename;
1020 $result = dol_delete_file($filetodelete);
1021 }
1022 }
1023
1024 if (dol_is_dir_empty($dirtodelete)) {
1025 dol_delete_dir($dirtodelete);
1026 }
1027
1028 // Update descriptor file to comment file
1029 if (in_array($tab, array('css', 'js'))) {
1030 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1031 $arrayreplacement = array('/^\s*\''.preg_quote('/'.$relativefilename, '/').'\',*/m' => ' // \'/'.$relativefilename.'\',');
1032 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1033 }
1034
1035 if (preg_match('/_extrafields/', $relativefilename)) {
1036 // Now we update the object file to set $isextrafieldmanaged to 0
1037 $srcfile = $dirins.'/'.strtolower($module).'/class/'.strtolower($objectname).'.class.php';
1038 $arrayreplacement = array('/\$isextrafieldmanaged = 1;/' => '$isextrafieldmanaged = 0;');
1039 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1040 }
1041
1042 // Now we update the lib file to set $showtabofpagexxx to 0
1043 $varnametoupdate = '';
1044 $reg = array();
1045 if (preg_match('/_([a-z]+)\.php$/', $relativefilename, $reg)) {
1046 $varnametoupdate = 'showtabofpage'.$reg[1];
1047 }
1048 if ($varnametoupdate) {
1049 $srcfile = $dirins.'/'.strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php';
1050 $arrayreplacement = array('/\$'.preg_quote($varnametoupdate, '/').' = 1;/' => '$'.preg_quote($varnametoupdate, '/').' = 0;');
1051 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1052 }
1053 }
1054 }
1055}
1056
1057// Init an object
1058if ($dirins && $action == 'initobject' && $module && $objectname && $user->hasRight("modulebuilder", "run")) {
1059 $warning = 0;
1060
1061 $objectname = ucfirst($objectname);
1062
1063 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1064 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1065
1066 if (preg_match('/[^a-z0-9_]/i', $objectname)) {
1067 $error++;
1068 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1069 $tabobj = 'newobject';
1070 }
1071 if (class_exists($objectname)) {
1072 // TODO Add a more efficient detection. Scan disk ?
1073 $error++;
1074 setEventMessages($langs->trans("AnObjectWithThisClassNameAlreadyExists"), null, 'errors');
1075 $tabobj = 'newobject';
1076 }
1077
1078 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
1079 $destdir = $dirins.'/'.strtolower($module);
1080
1081 // The dir was not created by init
1082 dol_mkdir($destdir.'/class');
1083 dol_mkdir($destdir.'/img');
1084 dol_mkdir($destdir.'/lib');
1085 dol_mkdir($destdir.'/scripts');
1086 dol_mkdir($destdir.'/sql');
1087
1088 // Scan dir class to find if an object with the same name already exists.
1089 if (!$error) {
1090 $dirlist = dol_dir_list($destdir.'/class', 'files', 0, '\.txt$');
1091 $alreadyfound = false;
1092 foreach ($dirlist as $key => $val) {
1093 $filefound = preg_replace('/\.txt$/', '', $val['name']);
1094 if (strtolower($objectname) == strtolower($filefound) && $objectname != $filefound) {
1095 $alreadyfound = true;
1096 $error++;
1097 setEventMessages($langs->trans("AnObjectAlreadyExistWithThisNameAndDiffCase"), null, 'errors');
1098 break;
1099 }
1100 }
1101 }
1102
1103 // If we must reuse an existing table for properties, define $stringforproperties
1104 // Generate class file from the table
1105 $stringforproperties = '';
1106 $tablename = GETPOST('initfromtablename', 'alpha');
1107 if ($tablename) {
1108 $_results = $db->DDLDescTable($tablename);
1109 if (empty($_results)) {
1110 $error++;
1111 $langs->load("errors");
1112 setEventMessages($langs->trans("ErrorTableNotFound", $tablename), null, 'errors');
1113 } else {
1141 /*public $fields=array(
1142 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'index' => 1, 'position' => 1, 'comment' => 'Id'),
1143 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'showoncombobox' => 1, 'index' => 1, 'position' => 10, 'searchall' => 1, 'comment' => 'Reference of object'),
1144 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'default' => 1, 'notnull' => 1, 'index' => 1, 'position' => 20),
1145 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'position' => 30, 'searchall' => 1, 'css' => 'minwidth200', 'help' => 'Help text', 'alwayseditable' => '1'),
1146 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'visible' => 1, 'default' => 'null', 'position' => 40, 'searchall' => 0, 'isameasure' => 1, 'help' => 'Help text'),
1147 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'visible' => 1, 'enabled' => 1, 'position' => 50, 'notnull' => -1, 'index' => 1, 'searchall' => 1, 'help' => 'LinkToThirdparty'),
1148 'description' => array('type' => 'text', 'label' => 'Descrption', 'enabled' => 1, 'visible' => 0, 'position' => 60),
1149 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 61),
1150 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 62),
1151 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 500),
1152 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 501),
1153 //'date_valid' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 502),
1154 'fk_user_creat' => array('type' => 'integer', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 510),
1155 'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 511),
1156 //'fk_user_valid' => array('type' => 'integer', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 512),
1157 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'index' => 0, 'position' => 1000),
1158 'status' => array('type' => 'integer', 'label' => 'Status', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'default' => 0, 'index' => 1, 'position' => 1000, 'arrayofkeyval' => array(0 => 'Draft', 1 => 'Active', -1 => 'Cancel')),
1159 );*/
1160
1161 $stringforproperties = '// BEGIN MODULEBUILDER PROPERTIES'."\n";
1162 $stringforproperties .= 'public $fields = array('."\n";
1163 $i = 10;
1164 while ($obj = $db->fetch_object($_results)) {
1165 // fieldname
1166 $fieldname = $obj->Field;
1167 // type
1168 $type = $obj->Type;
1169 if ($type == 'int(11)') {
1170 $type = 'integer';
1171 }
1172 if ($type == 'float') {
1173 $type = 'real';
1174 }
1175 if (strstr($type, 'tinyint')) {
1176 $type = 'integer';
1177 }
1178 if ($obj->Field == 'fk_soc') {
1179 $type = 'integer:Societe:societe/class/societe.class.php';
1180 }
1181 if (preg_match('/^fk_proj/', $obj->Field)) {
1182 $type = 'integer:Project:projet/class/project.class.php:1:fk_statut=1';
1183 }
1184 if (preg_match('/^fk_prod/', $obj->Field)) {
1185 $type = 'integer:Product:product/class/product.class.php:1';
1186 }
1187 if ($obj->Field == 'fk_warehouse') {
1188 $type = 'integer:Entrepot:product/stock/class/entrepot.class.php';
1189 }
1190 if (preg_match('/^(fk_user|fk_commercial)/', $obj->Field)) {
1191 $type = 'integer:User:user/class/user.class.php';
1192 }
1193
1194 // notnull
1195 $notnull = ($obj->Null == 'YES' ? 0 : 1);
1196 if ($fieldname == 'fk_user_modif') {
1197 $notnull = -1;
1198 }
1199 // label
1200 $label = preg_replace('/_/', '', ucfirst($fieldname));
1201 if ($fieldname == 'rowid') {
1202 $label = 'TechnicalID';
1203 }
1204 if ($fieldname == 'import_key') {
1205 $label = 'ImportId';
1206 }
1207 if ($fieldname == 'fk_soc') {
1208 $label = 'ThirdParty';
1209 }
1210 if ($fieldname == 'tms') {
1211 $label = 'DateModification';
1212 }
1213 if ($fieldname == 'datec') {
1214 $label = 'DateCreation';
1215 }
1216 if ($fieldname == 'date_valid') {
1217 $label = 'DateValidation';
1218 }
1219 if ($fieldname == 'datev') {
1220 $label = 'DateValidation';
1221 }
1222 if ($fieldname == 'note_private') {
1223 $label = 'NotePublic';
1224 }
1225 if ($fieldname == 'note_public') {
1226 $label = 'NotePrivate';
1227 }
1228 if ($fieldname == 'fk_user_creat') {
1229 $label = 'UserAuthor';
1230 }
1231 if ($fieldname == 'fk_user_modif') {
1232 $label = 'UserModif';
1233 }
1234 if ($fieldname == 'fk_user_valid') {
1235 $label = 'UserValidation';
1236 }
1237 // visible
1238 $visible = -1;
1239 if (in_array($fieldname, array('ref', 'label'))) {
1240 $visible = 1;
1241 }
1242 if ($fieldname == 'entity') {
1243 $visible = -2;
1244 }
1245 if ($fieldname == 'entity') {
1246 $visible = -2;
1247 }
1248 if ($fieldname == 'import_key') {
1249 $visible = -2;
1250 }
1251 if ($fieldname == 'fk_user_creat') {
1252 $visible = -2;
1253 }
1254 if ($fieldname == 'fk_user_modif') {
1255 $visible = -2;
1256 }
1257 if (in_array($fieldname, array('ref_ext', 'model_pdf', 'note_public', 'note_private'))) {
1258 $visible = 0;
1259 }
1260 // enabled
1261 $enabled = 1;
1262 // default
1263 $default = '';
1264 if ($fieldname == 'entity') {
1265 $default = 1;
1266 }
1267 // position
1268 $position = $i;
1269 if (in_array($fieldname, array('status', 'statut', 'fk_status', 'fk_statut'))) {
1270 $position = 500;
1271 }
1272 if ($fieldname == 'import_key') {
1273 $position = 900;
1274 }
1275 // $alwayseditable
1276 if ($fieldname == 'label') {
1277 $alwayseditable = 1;
1278 } else {
1279 $alwayseditable = 0;
1280 }
1281 // index
1282 $index = 0;
1283 if ($fieldname == 'entity') {
1284 $index = 1;
1285 }
1286 // css, cssview, csslist
1287 $css = '';
1288 $cssview = '';
1289 $csslist = '';
1290 if (preg_match('/^fk_/', $fieldname)) {
1291 $css = 'maxwidth500 widthcentpercentminusxx';
1292 }
1293 if ($fieldname == 'label') {
1294 $css = 'minwidth300';
1295 $cssview = 'wordbreak';
1296 }
1297 if (in_array($fieldname, array('note_public', 'note_private'))) {
1298 $cssview = 'wordbreak';
1299 }
1300 if (in_array($fieldname, array('ref', 'label')) || preg_match('/integer:/', $type)) {
1301 $csslist = 'tdoverflowmax150';
1302 }
1303
1304 // type
1305 $picto = $obj->Picto;
1306 if ($obj->Field == 'fk_soc') {
1307 $picto = 'company';
1308 }
1309 if (preg_match('/^fk_proj/', $obj->Field)) {
1310 $picto = 'project';
1311 }
1312
1313 // Build the property string
1314 $stringforproperties .= "'".$obj->Field."' => array('type' => '".$type."', 'label' => '".$label."',";
1315 if ($default != '') {
1316 $stringforproperties .= " 'default' => ".$default.",";
1317 }
1318 $stringforproperties .= " 'enabled' => ".$enabled.",";
1319 $stringforproperties .= " 'visible' => ".$visible;
1320 if ($notnull) {
1321 $stringforproperties .= ", 'notnull' => ".$notnull;
1322 }
1323 if ($alwayseditable) {
1324 $stringforproperties .= ", 'alwayseditable' => 1";
1325 }
1326 if ($fieldname == 'ref' || $fieldname == 'code') {
1327 $stringforproperties .= ", 'showoncombobox' => 1";
1328 }
1329 $stringforproperties .= ", 'position' => ".$position;
1330 if ($index) {
1331 $stringforproperties .= ", 'index' => ".$index;
1332 }
1333 if ($picto) {
1334 $stringforproperties .= ", 'picto' => '".$picto."'";
1335 }
1336 if ($css) {
1337 $stringforproperties .= ", 'css' => '".$css."'";
1338 }
1339 if ($cssview) {
1340 $stringforproperties .= ", 'cssview' => '".$cssview."'";
1341 }
1342 if ($csslist) {
1343 $stringforproperties .= ", 'csslist' => '".$csslist."'";
1344 }
1345 $stringforproperties .= "),\n";
1346 $i += 5;
1347 }
1348 $stringforproperties .= ');'."\n";
1349 $stringforproperties .= '// END MODULEBUILDER PROPERTIES'."\n";
1350 }
1351 }
1352
1353 $filetogenerate = array(); // For static analysis
1354 if (!$error) {
1355 // Copy some files
1356 $filetogenerate = array(
1357 'myobject_card.php' => strtolower($objectname).'_card.php',
1358 'myobject_note.php' => strtolower($objectname).'_note.php',
1359 'myobject_contact.php' => strtolower($objectname).'_contact.php',
1360 'myobject_document.php' => strtolower($objectname).'_document.php',
1361 'myobject_agenda.php' => strtolower($objectname).'_agenda.php',
1362 'myobject_list.php' => strtolower($objectname).'_list.php',
1363 'admin/myobject_extrafields.php' => 'admin/'.strtolower($objectname).'_extrafields.php',
1364 'lib/mymodule_myobject.lib.php' => 'lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php',
1365 //'test/phpunit/MyObjectTest.php' => 'test/phpunit/'.strtolower($objectname).'Test.php',
1366 'sql/llx_mymodule_myobject.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql',
1367 'sql/llx_mymodule_myobject.key.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql',
1368 'sql/llx_mymodule_myobject_extrafields.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql',
1369 'sql/llx_mymodule_myobject_extrafields.key.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql',
1370 //'scripts/mymodule.php' => 'scripts/'.strtolower($objectname).'.php',
1371 'class/myobject.class.php' => 'class/'.strtolower($objectname).'.class.php',
1372 //'class/api_mymodule.class.php' => 'class/api_'.strtolower($module).'.class.php',
1373 );
1374
1375 if (GETPOST('includerefgeneration', 'aZ09')) {
1376 dol_mkdir($destdir.'/core/modules/'.strtolower($module));
1377
1378 $filetogenerate += array(
1379 'core/modules/mymodule/mod_myobject_advanced.php' => 'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_advanced.php',
1380 'core/modules/mymodule/mod_myobject_standard.php' => 'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_standard.php',
1381 'core/modules/mymodule/modules_myobject.php' => 'core/modules/'.strtolower($module).'/modules_'.strtolower($objectname).'.php',
1382 );
1383 }
1384 if (GETPOST('includedocgeneration', 'aZ09')) {
1385 dol_mkdir($destdir.'/core/modules/'.strtolower($module));
1386 dol_mkdir($destdir.'/core/modules/'.strtolower($module).'/doc');
1387
1388 $filetogenerate += array(
1389 'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php' => 'core/modules/'.strtolower($module).'/doc/doc_generic_'.strtolower($objectname).'_odt.modules.php',
1390 'core/modules/mymodule/doc/pdf_standard_myobject.modules.php' => 'core/modules/'.strtolower($module).'/doc/pdf_standard_'.strtolower($objectname).'.modules.php'
1391 );
1392 }
1393 if (GETPOST('generatepermissions', 'aZ09')) {
1394 $firstobjectname = 'myobject';
1395 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1396 dol_include_once($pathtofile);
1397 $class = 'mod'.$module;
1398 $moduleobj = null;
1399 if (class_exists($class)) {
1400 try {
1401 $moduleobj = new $class($db);
1402 '@phan-var-force DolibarrModules $moduleobj';
1403 } catch (Exception $e) {
1404 $error++;
1405 dol_print_error($db, $e->getMessage());
1406 }
1407 }
1408 if (is_object($moduleobj)) {
1409 $rights = $moduleobj->rights;
1410 } else {
1411 $rights = [];
1412 }
1413 $moduledescriptorfile = $destdir.'/core/modules/mod'.$module.'.class.php';
1414 $checkComment = checkExistComment($moduledescriptorfile, 1);
1415 if ($checkComment < 0) {
1416 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
1417 } else {
1418 $generatePerms = reWriteAllPermissions($moduledescriptorfile, $rights, null, null, $objectname, $module, -2);
1419 if ($generatePerms < 0) {
1420 setEventMessages($langs->trans("WarningPermissionAlreadyExist", $langs->transnoentities($objectname)), null, 'warnings');
1421 }
1422 }
1423 }
1424
1425 if (!$error) {
1426 foreach ($filetogenerate as $srcfile => $destfile) {
1427 $result = dol_copy($srcdir.'/'.$srcfile, $destdir.'/'.$destfile, $newmask, 0);
1428 if ($result <= 0) {
1429 if ($result < 0) {
1430 $warning++;
1431 $langs->load("errors");
1432 setEventMessages($langs->trans("ErrorFailToCopyFile", $srcdir.'/'.$srcfile, $destdir.'/'.$destfile), null, 'errors');
1433 } else {
1434 // $result == 0
1435 setEventMessages($langs->trans("FileAlreadyExists", $destfile), null, 'warnings');
1436 }
1437 }
1438 $arrayreplacement = array(
1439 '/myobject\.class\.php/' => strtolower($objectname).'.class.php',
1440 '/myobject\.lib\.php/' => strtolower($objectname).'.lib.php',
1441 );
1442
1443 dolReplaceInFile($destdir.'/'.$destfile, $arrayreplacement, '', '0', 0, 1);
1444 }
1445 }
1446
1447 // Replace property section with $stringforproperties
1448 if (!$error && $stringforproperties) {
1449 //var_dump($stringforproperties);exit;
1450 $arrayreplacement = array(
1451 '/\/\/ BEGIN MODULEBUILDER PROPERTIES.*\/\/ END MODULEBUILDER PROPERTIES/ims' => $stringforproperties
1452 );
1453
1454 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1455 }
1456
1457 // Edit the class 'class/'.strtolower($objectname).'.class.php'
1458 if (GETPOST('includerefgeneration', 'aZ09')) {
1459 // Replace 'visible' => 1, 'noteditable' => 0, 'default' => ''
1460 $arrayreplacement = array(
1461 '/\'visible\'s*=>s*1,\s*\'noteditable\'s*=>s*0,\s*\'default\'s*=>s*\'\'/' => "'visible' => 4, 'noteditable' => 1, 'default' => '(PROV)'"
1462 );
1463 //var_dump($arrayreplacement);exit;
1464 //var_dump($destdir.'/class/'.strtolower($objectname).'.class.php');exit;
1465 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1466
1467 $arrayreplacement = array(
1468 '/\'models\' => 0,/' => '\'models\' => 1,'
1469 );
1470 dolReplaceInFile($destdir.'/core/modules/mod'.$module.'.class.php', $arrayreplacement, '', '0', 0, 1);
1471 }
1472
1473 // Edit the setup file and the card page
1474 if (GETPOST('includedocgeneration', 'aZ09')) {
1475 // Replace some var init into some files
1476 $arrayreplacement = array(
1477 '/\$includedocgeneration = 0;/' => '$includedocgeneration = 1;'
1478 );
1479 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1480 dolReplaceInFile($destdir.'/'.strtolower($objectname).'_card.php', $arrayreplacement, '', '0', 0, 1);
1481
1482 $arrayreplacement = array(
1483 '/\'models\' => 0,/' => '\'models\' => 1,'
1484 );
1485
1486 dolReplaceInFile($destdir.'/core/modules/mod'.$module.'.class.php', $arrayreplacement, '', '0', 0, 1);
1487 }
1488
1489 // TODO Update entries '$myTmpObjects['MyObject'] = array('includerefgeneration' => 0, 'includedocgeneration' => 0);'
1490
1491
1492 // Scan for object class files
1493 $listofobject = dol_dir_list($destdir.'/class', 'files', 0, '\.class\.php$');
1494
1495 $firstobjectname = '';
1496 foreach ($listofobject as $fileobj) {
1497 if (preg_match('/^api_/', $fileobj['name'])) {
1498 continue;
1499 }
1500 if (preg_match('/^actions_/', $fileobj['name'])) {
1501 continue;
1502 }
1503
1504 $tmpcontent = file_get_contents($fileobj['fullname']);
1505 $reg = array();
1506 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
1507 $objectnameloop = $reg[1];
1508 if (empty($firstobjectname)) {
1509 $firstobjectname = $objectnameloop;
1510 }
1511 }
1512
1513 // Regenerate left menu entry in descriptor for $objectname
1514 $stringtoadd = "
1515 \$this->menu[\$r++] = array(
1516 'fk_menu' => 'fk_mainmenu=mymodule',
1517 'type' => 'left',
1518 'titre' => 'MyObject',
1519 'prefix' => img_picto('', \$this->picto, 'class=\"paddingright pictofixedwidth valignmiddle\"'),
1520 'mainmenu' => 'mymodule',
1521 'leftmenu' => 'myobject',
1522 'url' => '/mymodule/myobject_list.php',
1523 'langs' => 'mymodule@mymodule',
1524 'position' => 1000 + \$r,
1525 'enabled' => 'isModEnabled(\"mymodule\")',
1526 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "read")' : '1')."',
1527 'target' => '',
1528 'user' => 2,
1529 'object' => 'MyObject'
1530 );
1531 \$this->menu[\$r++] = array(
1532 'fk_menu' => 'fk_mainmenu=mymodule,fk_leftmenu=myobject',
1533 'type' => 'left',
1534 'titre' => 'List MyObject',
1535 'mainmenu' => 'mymodule',
1536 'leftmenu' => 'mymodule_myobject_list',
1537 'url' => '/mymodule/myobject_list.php',
1538 'langs' => 'mymodule@mymodule',
1539 'position' => 1000 + \$r,
1540 'enabled' => 'isModEnabled(\"mymodule\")',
1541 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "read")' : '1')."',
1542 'target' => '',
1543 'user' => 2,
1544 'object' => 'MyObject'
1545 );
1546 \$this->menu[\$r++] = array(
1547 'fk_menu' => 'fk_mainmenu=mymodule,fk_leftmenu=myobject',
1548 'type' => 'left',
1549 'titre' => 'New MyObject',
1550 'mainmenu' => 'mymodule',
1551 'leftmenu' => 'mymodule_myobject_new',
1552 'url' => '/mymodule/myobject_card.php?action=create',
1553 'langs' => 'mymodule@mymodule',
1554 'position' => 1000 + \$r,
1555 'enabled' => 'isModEnabled(\"mymodule\")',
1556 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "write")' : '1')."',
1557 'target' => '',
1558 'user' => 2,
1559 'object' => 'MyObject'
1560 );";
1561 $stringtoadd = preg_replace('/MyObject/', $objectname, $stringtoadd);
1562 $stringtoadd = preg_replace('/mymodule/', strtolower($module), $stringtoadd);
1563 $stringtoadd = preg_replace('/myobject/', strtolower($objectname), $stringtoadd);
1564
1565 $moduledescriptorfile = $destdir.'/core/modules/mod'.$module.'.class.php';
1566 }
1567 // TODO Allow a replace with regex using dolReplaceInFile with param arryreplacementisregex to 1
1568 // TODO Avoid duplicate addition
1569
1570 // load class and check if menu exist with same object name
1571 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1572 dol_include_once($pathtofile);
1573 $class = 'mod'.$module;
1574 $moduleobj = null;
1575 if (class_exists($class)) {
1576 try {
1577 $moduleobj = new $class($db);
1578 '@phan-var-force DolibarrModules $moduleobj';
1579 } catch (Exception $e) {
1580 $error++;
1581 dol_print_error($db, $e->getMessage());
1582 }
1583 }
1584 if (is_object($moduleobj)) {
1585 $menus = $moduleobj->menu;
1586 } else {
1587 $menus = array();
1588 }
1589 $counter = 0 ;
1590 foreach ($menus as $menu) {
1591 if ($menu['leftmenu'] == strtolower($objectname)) {
1592 $counter++;
1593 }
1594 }
1595 if (!$counter) {
1596 $checkComment = checkExistComment($moduledescriptorfile, 0);
1597 if ($checkComment < 0) {
1598 $warning++;
1599 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), basename($moduledescriptorfile)), null, 'warnings');
1600 } else {
1601 $arrayofreplacement = array('/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT */' => '/* BEGIN MODULEBUILDER LEFTMENU '.strtoupper($objectname).' */'.$stringtoadd."\n\t\t".'/* END MODULEBUILDER LEFTMENU '.strtoupper($objectname).' */'."\n\t\t".'/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT */');
1602 dolReplaceInFile($moduledescriptorfile, $arrayofreplacement);
1603 }
1604 }
1605 // Add module descriptor to list of files to replace "MyObject' string with real name of object.
1606 $filetogenerate[] = 'core/modules/mod'.$module.'.class.php';
1607 }
1608
1609 if (!$error) {
1610 // Edit PHP files to make replacement
1611 foreach ($filetogenerate as $destfile) {
1612 $phpfileval['fullname'] = $destdir.'/'.$destfile;
1613
1614 //var_dump($phpfileval['fullname']);
1615 $arrayreplacement = array(
1616 'mymodule' => strtolower($module),
1617 'MyModule' => $module,
1618 'MYMODULE' => strtoupper($module),
1619 'My module' => $module,
1620 'my module' => $module,
1621 'mon module' => $module,
1622 'Mon module' => $module,
1623 'htdocs/modulebuilder/template/' => strtolower($modulename),
1624 'myobject' => strtolower($objectname),
1625 'MyObject' => $objectname,
1626 //'MYOBJECT' => strtoupper($objectname),
1627 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
1628 );
1629
1630 if (getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')) {
1631 $arrayreplacement['---Replace with your own copyright and developer email---'] = dol_print_date($now, '%Y').' ' . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR');
1632 }
1633
1634 $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement);
1635 //var_dump($result);
1636 if ($result < 0) {
1637 setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
1638 }
1639 }
1640 }
1641
1642 if (!$error) {
1643 // Edit the class file to write properties
1644 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask);
1645
1646 if (is_numeric($object) && $object <= 0) {
1647 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1648 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1649 $warning++;
1650 }
1651 // check if documentation was generate and add table of properties object
1652 $file = $destdir.'/class/'.strtolower($objectname).'.class.php';
1653 $destfile = $destdir.'/doc/Documentation.asciidoc';
1654
1655 if (file_exists($destfile)) {
1656 writePropsInAsciiDoc($file, $objectname, $destfile);
1657 }
1658 }
1659 if (!$error) {
1660 // Edit sql with new properties
1661 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, '', $object);
1662
1663 if ($result <= 0) {
1664 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null);
1665 $error++;
1666 }
1667 }
1668
1669 if (!$error) {
1670 setEventMessages($langs->trans('FilesForObjectInitialized', $objectname), null);
1671 $tabobj = $objectname;
1672 } else {
1673 $tabobj = 'newobject';
1674 }
1675
1676 // check if module is enabled
1677 if (isModEnabled(strtolower($module))) {
1678 $result = unActivateModule(strtolower($module));
1679 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
1680 if ($result) {
1681 setEventMessages($result, null, 'errors');
1682 }
1683 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
1684 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module);
1685 exit;
1686 }
1687}
1688
1689// Add a dictionary
1690if ($dirins && $action == 'initdic' && $module && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
1691 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1692 $destdir = $dirins.'/'.strtolower($module);
1693 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1694
1695 if (!GETPOST('dicname')) {
1696 $error++;
1697 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Table")), null, 'errors');
1698 }
1699 if (!GETPOST('label')) {
1700 $error++;
1701 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
1702 }
1703 if (!$error) {
1704 $newdicname = $dicname;
1705 if (!preg_match('/^c_/', $newdicname)) {
1706 $newdicname = 'c_'.$dicname;
1707 }
1708 dol_include_once($pathtofile);
1709 $class = 'mod'.$module;
1710
1711 if (class_exists($class)) {
1712 try {
1713 $moduleobj = new $class($db);
1714 '@phan-var-force DolibarrModules $moduleobj';
1715 } catch (Exception $e) {
1716 $error++;
1717 dol_print_error($db, $e->getMessage());
1718 }
1719 } else {
1720 $error++;
1721 $langs->load("errors");
1722 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1723 exit;
1724 }
1725 $dictionaries = $moduleobj->dictionaries;
1726 $checkComment = checkExistComment($moduledescriptorfile, 2);
1727 if ($checkComment < 0) {
1728 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
1729 } else {
1730 createNewDictionnary($module, $moduledescriptorfile, $newdicname, $dictionaries);
1731 if (function_exists('opcache_invalidate')) {
1732 opcache_reset(); // remove the include cache hell !
1733 }
1734 clearstatcache(true);
1735 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
1736 exit;
1737 }
1738 }
1739}
1740
1741// Delete a SQL table
1742if ($dirins && ($action == 'droptable' || $action == 'droptableextrafields') && !empty($module) && !empty($tabobj) && $user->hasRight("modulebuilder", "run")) {
1743 $objectname = $tabobj;
1744
1745 $arrayoftables = array();
1746 if ($action == 'droptable') { // Test on permission already done
1747 $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj);
1748 }
1749 if ($action == 'droptableextrafields') { // Test on permission already done
1750 $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj).'_extrafields';
1751 }
1752
1753 foreach ($arrayoftables as $tabletodrop) {
1754 $nb = -1;
1755 $sql = "SELECT COUNT(*) as nb FROM ".$tabletodrop;
1756 $resql = $db->query($sql);
1757 if ($resql) {
1758 $obj = $db->fetch_object($resql);
1759 if ($obj) {
1760 $nb = $obj->nb;
1761 }
1762 } else {
1763 if ($db->lasterrno() == 'DB_ERROR_NOSUCHTABLE') {
1764 setEventMessages($langs->trans("TableDoesNotExists", $tabletodrop), null, 'warnings');
1765 } else {
1766 dol_print_error($db);
1767 }
1768 }
1769 if ($nb == 0) {
1770 $resql = $db->DDLDropTable($tabletodrop);
1771 //var_dump($resql);
1772 setEventMessages($langs->trans("TableDropped", $tabletodrop), null, 'mesgs');
1773 } elseif ($nb > 0) {
1774 setEventMessages($langs->trans("TableNotEmptyDropCanceled", $tabletodrop), null, 'warnings');
1775 }
1776 }
1777}
1778
1779if ($dirins && $action == 'addproperty' && empty($cancel) && !empty($module) && (!empty($tabobj) || !empty(GETPOST('obj'))) && $user->hasRight("modulebuilder", "run")) {
1780 $error = 0;
1781
1782 $objectname = (GETPOST('obj') ? GETPOST('obj') : $tabobj);
1783
1784 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1785 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1786
1787 $srcdir = $dirread.'/'.strtolower($module);
1788 $destdir = $dirins.'/'.strtolower($module);
1789 dol_mkdir($destdir);
1790
1791 $objects = dolGetListOfObjectClasses($destdir);
1792 if (!in_array($objectname, array_values($objects))) {
1793 $error++;
1794 setEventMessages($langs->trans("ErrorObjectNotFound", $langs->transnoentities($objectname)), null, 'errors');
1795 }
1796
1797 $addfieldentry = array();
1798
1799 // We click on add property
1800 if (!GETPOST('regenerateclasssql') && !GETPOST('regeneratemissing')) {
1801 if (!GETPOST('propname', 'aZ09')) {
1802 $error++;
1803 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Name")), null, 'errors');
1804 }
1805 if (!GETPOST('proplabel', 'alpha')) {
1806 $error++;
1807 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
1808 }
1809 if (!GETPOST('proptype', 'alpha')) {
1810 $error++;
1811 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
1812 }
1813
1814
1815 if (!$error && !GETPOST('regenerateclasssql') && !GETPOST('regeneratemissing')) {
1816 $addfieldentry = array(
1817 'name' => GETPOST('propname', 'aZ09'),
1818 'label' => GETPOST('proplabel', 'alpha'),
1819 'type' => strtolower(GETPOST('proptype', 'alpha')),
1820 'arrayofkeyval' => GETPOST('proparrayofkeyval', 'alphawithlgt'), // Example json string '{"0":"Draft","1":"Active","-1":"Cancel"}'
1821 'visible' => GETPOST('propvisible', 'alphanohtml'),
1822 'enabled' => GETPOST('propenabled', 'alphanohtml'),
1823 'position' => GETPOSTINT('propposition'),
1824 'notnull' => GETPOSTINT('propnotnull'),
1825 'index' => GETPOSTINT('propindex'),
1826 'foreignkey' => GETPOST('propforeignkey', 'alpha'),
1827 'searchall' => GETPOSTINT('propsearchall'),
1828 'isameasure' => GETPOSTINT('propisameasure'),
1829 'comment' => GETPOST('propcomment', 'alpha'),
1830 'help' => GETPOST('prophelp', 'alpha'),
1831 'css' => GETPOST('propcss', 'alpha'), // Can be 'maxwidth500 widthcentpercentminusxx' for example
1832 'cssview' => GETPOST('propcssview', 'alpha'),
1833 'csslist' => GETPOST('propcsslist', 'alpha'),
1834 'default' => GETPOST('propdefault', 'restricthtml'),
1835 'noteditable' => GETPOSTINT('propnoteditable'),
1836 //'alwayseditable' => GETPOSTINT('propalwayseditable'),
1837 'validate' => GETPOSTINT('propvalidate')
1838 );
1839
1840 if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
1841 $tmpdecode = json_decode($addfieldentry['arrayofkeyval'], true);
1842 if ($tmpdecode) { // If string is already a json
1843 $addfieldentry['arrayofkeyval'] = $tmpdecode;
1844 } else { // If string is a list of lines with "key,value"
1845 $tmparray = dolExplodeIntoArray($addfieldentry['arrayofkeyval'], "\n", ",");
1846 $addfieldentry['arrayofkeyval'] = $tmparray;
1847 }
1848 }
1849 }
1850 }
1851
1852 /*if (GETPOST('regeneratemissing'))
1853 {
1854 setEventMessages($langs->trans("FeatureNotYetAvailable"), null, 'warnings');
1855 $error++;
1856 }*/
1857
1858 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1859
1860 // Edit the class file to write properties
1861 if (!$error) {
1862 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, $addfieldentry, $moduletype);
1863
1864 if (is_numeric($object) && $object <= 0) {
1865 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1866 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1867 $error++;
1868 }
1869 }
1870
1871 // Edit sql with new properties
1872 if (!$error) {
1873 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object, $moduletype);
1874
1875 if ($result <= 0) {
1876 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1877 $error++;
1878 }
1879 }
1880
1881 if (!$error) {
1882 clearstatcache(true);
1883
1884 setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1885
1886 setEventMessages($langs->trans('WarningDatabaseIsNotUpdated'), null);
1887
1888 // Make a redirect to reload all data
1889 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname.'&nocache='.time());
1890 exit;
1891 }
1892}
1893
1894if ($dirins && $action == 'confirm_deleteproperty' && $propertykey && $user->hasRight("modulebuilder", "run")) {
1895 $objectname = $tabobj;
1896
1897 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1898 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1899
1900 $srcdir = $dirread.'/'.strtolower($module);
1901 $destdir = $dirins.'/'.strtolower($module);
1902 dol_mkdir($destdir);
1903
1904 // Edit the class file to write properties
1905 if (!$error) {
1906 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, array(), $propertykey);
1907
1908 if (is_numeric($object) && $object <= 0) {
1909 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1910 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1911 $error++;
1912 }
1913 }
1914
1915 // Edit sql with new properties
1916 if (!$error) {
1917 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object);
1918
1919 if ($result <= 0) {
1920 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1921 $error++;
1922 }
1923 }
1924
1925 if (!$error) {
1926 setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1927
1928 clearstatcache(true);
1929
1930 // Make a redirect to reload all data
1931 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname);
1932 exit;
1933 }
1934}
1935
1936if ($dirins && $action == 'confirm_deletemodule' && $user->hasRight("modulebuilder", "run")) {
1937 if (preg_match('/[^a-z0-9_]/i', $module)) {
1938 $error++;
1939 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1940 }
1941
1942 if (!$error) {
1943 $modulelowercase = strtolower($module);
1944
1945 // Dir for module
1946 $dir = $dirins.'/'.$modulelowercase;
1947
1948 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1949
1950 // Dir for module
1951 $dir = dol_buildpath($modulelowercase, 0);
1952
1953 // Zip file to build
1954 $FILENAMEZIP = '';
1955
1956 // Load module
1957 dol_include_once($pathtofile);
1958 $class = 'mod'.$module;
1959
1960 $moduleobj = null;
1961
1962 if (class_exists($class)) {
1963 try {
1964 $moduleobj = new $class($db);
1965 '@phan-var-force DolibarrMOdules $moduleobj';
1966 } catch (Exception $e) {
1967 $error++;
1968 dol_print_error($db, $e->getMessage());
1969 }
1970 } else {
1971 $error++;
1972 $langs->load("errors");
1973 setEventMessages($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module), null, 'warnings');
1974 }
1975
1976 if ($moduleobj) {
1977 $moduleobj->remove();
1978 }
1979
1980 $result = dol_delete_dir_recursive($dir);
1981
1982 if ($result > 0) {
1983 setEventMessages($langs->trans("DirWasRemoved", $modulelowercase), null);
1984
1985 clearstatcache(true);
1986 if (function_exists('opcache_invalidate')) {
1987 opcache_reset(); // remove the include cache hell !
1988 }
1989
1990 header("Location: ".$_SERVER["PHP_SELF"].'?module=deletemodule');
1991 exit;
1992 } else {
1993 setEventMessages($langs->trans("PurgeNothingToDelete"), null, 'warnings');
1994 }
1995 }
1996
1997 $action = '';
1998 $module = 'deletemodule';
1999}
2000
2001if ($dirins && $action == 'confirm_deleteobject' && $objectname && $user->hasRight("modulebuilder", "run")) {
2002 if (preg_match('/[^a-z0-9_]/i', $objectname)) {
2003 $error++;
2004 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2005 }
2006
2007 if (!$error) {
2008 $modulelowercase = strtolower($module);
2009 $objectlowercase = strtolower($objectname);
2010
2011 // Dir for module
2012 $dir = $dirins.'/'.$modulelowercase;
2013
2014 // Delete some files
2015 $filetodelete = array(
2016 'myobject_card.php' => strtolower($objectname).'_card.php',
2017 'myobject_note.php' => strtolower($objectname).'_note.php',
2018 'myobject_contact.php' => strtolower($objectname).'_contact.php',
2019 'myobject_document.php' => strtolower($objectname).'_document.php',
2020 'myobject_agenda.php' => strtolower($objectname).'_agenda.php',
2021 'myobject_list.php' => strtolower($objectname).'_list.php',
2022 'admin/myobject_extrafields.php' => 'admin/'.strtolower($objectname).'_extrafields.php',
2023 'lib/mymodule_myobject.lib.php' => 'lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php',
2024 'test/phpunit/MyObjectTest.php' => 'test/phpunit/'.strtolower($objectname).'Test.php',
2025 'sql/llx_mymodule_myobject.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql',
2026 'sql/llx_mymodule_myobject_extrafields.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql',
2027 'sql/llx_mymodule_myobject.key.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql',
2028 'sql/llx_mymodule_myobject_extrafields.key.sql' => 'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql',
2029 'scripts/myobject.php' => 'scripts/'.strtolower($objectname).'.php',
2030 'class/myobject.class.php' => 'class/'.strtolower($objectname).'.class.php',
2031 'class/api_myobject.class.php' => 'class/api_'.strtolower($module).'.class.php',
2032 'core/modules/mymodule/mod_myobject_advanced.php' => 'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_advanced.php',
2033 'core/modules/mymodule/mod_myobject_standard.php' => 'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_standard.php',
2034 'core/modules/mymodule/modules_myobject.php' => 'core/modules/'.strtolower($module).'/modules_'.strtolower($objectname).'.php',
2035 'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php' => 'core/modules/'.strtolower($module).'/doc/doc_generic_'.strtolower($objectname).'_odt.modules.php',
2036 'core/modules/mymodule/doc/pdf_standard_myobject.modules.php' => 'core/modules/'.strtolower($module).'/doc/pdf_standard_'.strtolower($objectname).'.modules.php'
2037 );
2038
2039 //menu for the object selected
2040 // load class and check if menu,permission,documentation exist for this object
2041 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2042 dol_include_once($pathtofile);
2043 $class = 'mod'.$module;
2044 $moduleobj = null;
2045 if (class_exists($class)) {
2046 try {
2047 $moduleobj = new $class($db);
2048 '@phan-var-force DolibarrMOdules $moduleobj';
2049 } catch (Exception $e) {
2050 $error++;
2051 dol_print_error($db, $e->getMessage());
2052 }
2053 }
2054 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2055
2056 // delete menus linked to the object
2057 $menus = $moduleobj->menu;
2058 $rewriteMenu = checkExistComment($moduledescriptorfile, 0);
2059
2060 if ($rewriteMenu < 0) {
2061 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
2062 } else {
2063 reWriteAllMenus($moduledescriptorfile, $menus, $objectname, null, -1);
2064 }
2065
2066 // regenerate permissions and delete them
2067 $permissions = $moduleobj->rights;
2068 $rewritePerms = checkExistComment($moduledescriptorfile, 1);
2069 if ($rewritePerms < 0) {
2070 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2071 } else {
2072 reWriteAllPermissions($moduledescriptorfile, $permissions, null, null, $objectname, '', -1);
2073 }
2074 if ($rewritePerms && $rewriteMenu) {
2075 // check if documentation has been generated
2076 $file_doc = $dirins.'/'.strtolower($module).'/doc/Documentation.asciidoc';
2077 deletePropsAndPermsFromDoc($file_doc, $objectname);
2078
2079 clearstatcache(true);
2080 if (function_exists('opcache_invalidate')) {
2081 opcache_reset(); // remove the include cache hell !
2082 }
2083 $resultko = 0;
2084 foreach ($filetodelete as $tmpfiletodelete) {
2085 $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete, 0, 0, 1);
2086 $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete.'.back', 0, 0, 1);
2087 if (!$resulttmp) {
2088 $resultko++;
2089 }
2090 }
2091
2092 if ($resultko == 0) {
2093 setEventMessages($langs->trans("FilesDeleted"), null);
2094 } else {
2095 setEventMessages($langs->trans("ErrorSomeFilesCouldNotBeDeleted"), null, 'warnings');
2096 }
2097 }
2098 }
2099
2100 $action = '';
2101 if (! $error) {
2102 $tabobj = 'newobject';
2103 } else {
2104 $tabobj = 'deleteobject';
2105 }
2106
2107 // check if module is enabled
2108 if (isModEnabled(strtolower($module))) {
2109 $result = unActivateModule(strtolower($module));
2110 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2111 if ($result) {
2112 setEventMessages($result, null, 'errors');
2113 }
2114 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2115 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&tabobj=deleteobject&module='.urlencode($module));
2116 exit;
2117 }
2118}
2119
2120if (($dirins && $action == 'confirm_deletedictionary' && $dicname) || ($dirins && $action == 'confirm_deletedictionary' && GETPOST('dictionnarykey')) && $user->hasRight("modulebuilder", "run")) {
2121 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2122 $destdir = $dirins.'/'.strtolower($module);
2123 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2124
2125 if (preg_match('/[^a-z0-9_]/i', $dicname)) {
2126 $error++;
2127 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2128 }
2129
2130 if (!empty($dicname)) {
2131 $newdicname = $dicname;
2132 if (!preg_match('/^c_/', $newdicname)) {
2133 $newdicname = 'c_'.strtolower($dicname);
2134 }
2135 } else {
2136 $newdicname = null;
2137 }
2138
2139 dol_include_once($pathtofile);
2140 $class = 'mod'.$module;
2141
2142 if (class_exists($class)) {
2143 try {
2144 $moduleobj = new $class($db);
2145 '@phan-var-force DolibarrModules $moduleobj';
2146 } catch (Exception $e) {
2147 $error++;
2148 dol_print_error($db, $e->getMessage());
2149 }
2150 } else {
2151 $error++;
2152 $langs->load("errors");
2153 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2154 exit;
2155 }
2156
2157 $dicts = $moduleobj->dictionaries;
2158 $checkComment = checkExistComment($moduledescriptorfile, 2);
2159 if ($checkComment < 0) {
2160 $error++;
2161 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
2162 }
2163
2164 if (!empty(GETPOST('dictionnarykey'))) {
2165 $newdicname = $dicts['tabname'][GETPOSTINT('dictionnarykey') - 1];
2166 }
2167
2168 // Lookup the table dicname
2169 $checkTable = false;
2170 if ($newdicname !== null) {
2171 $checkTable = $db->DDLDescTable(MAIN_DB_PREFIX.strtolower($newdicname));
2172 }
2173
2174 if (is_bool($checkTable) || $db->num_rows($checkTable) <= 0) { // @phpstan-ignore-line
2175 $error++;
2176 }
2177
2178 // search the key by name
2179 $keyToDelete = null;
2180 foreach ($dicts['tabname'] as $key => $table) {
2181 //var_dump($table." /////// ".$newdicname);exit;
2182 if (strtolower($table) === $newdicname) {
2183 $keyToDelete = $key;
2184 break;
2185 }
2186 }
2187 // delete all dicname's key values from the dictionary
2188 if ($keyToDelete !== null) {
2189 $keysToDelete = ['tabname', 'tablib', 'tabsql', 'tabsqlsort', 'tabfield', 'tabfieldvalue', 'tabfieldinsert', 'tabrowid', 'tabcond', 'tabhelp'];
2190 foreach ($keysToDelete as $key) {
2191 unset($dicts[$key][$keyToDelete]);
2192 }
2193 } else {
2194 $error++;
2195 setEventMessages($langs->trans("ErrorDictionaryNotFound", ucfirst($dicname)), null, 'errors');
2196 }
2197 if (!$error) {
2198 // delete table
2199 $_results = $db->DDLDropTable(MAIN_DB_PREFIX.strtolower($newdicname));
2200 if ($_results < 0) {
2201 dol_print_error($db);
2202 $langs->load("errors");
2203 setEventMessages($langs->trans("ErrorTableNotFound", $newdicname), null, 'errors');
2204 }
2205 // rebuild file after update dictionaries
2206 $result = updateDictionaryInFile($module, $moduledescriptorfile, $dicts);
2207 if ($result > 0) {
2208 setEventMessages($langs->trans("DictionaryDeleted", ucfirst(substr($newdicname, 2))), null);
2209 }
2210 if (function_exists('opcache_invalidate')) {
2211 opcache_reset(); // remove the include cache hell !
2212 }
2213 clearstatcache(true);
2214 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
2215 exit;
2216 }
2217}
2218if ($dirins && $action == 'updatedictionary' && GETPOST('dictionnarykey') && $user->hasRight("modulebuilder", "run")) {
2219 $keydict = GETPOSTINT('dictionnarykey') - 1 ;
2220
2221 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2222 $destdir = $dirins.'/'.strtolower($module);
2223 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2224 dol_include_once($pathtofile);
2225 $class = 'mod'.$module;
2226
2227 if (class_exists($class)) {
2228 try {
2229 $moduleobj = new $class($db);
2230 '@phan-var-force DolibarrMOdules $moduleobj';
2231 } catch (Exception $e) {
2232 $error++;
2233 dol_print_error($db, $e->getMessage());
2234 }
2235 } else {
2236 $error++;
2237 $langs->load("errors");
2238 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2239 exit;
2240 }
2241
2242 $dicts = $moduleobj->dictionaries;
2243 if (!empty(GETPOST('tablib')) && GETPOST('tablib') !== $dicts['tablib'][$keydict]) {
2244 $dicts['tablib'][$keydict] = ucfirst(strtolower(GETPOST('tablib')));
2245 $checkComment = checkExistComment($moduledescriptorfile, 2);
2246 if ($checkComment < 0) {
2247 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
2248 } else {
2249 $updateDict = updateDictionaryInFile($module, $moduledescriptorfile, $dicts);
2250 if ($updateDict > 0) {
2251 setEventMessages($langs->trans("DictionaryNameUpdated", ucfirst(GETPOST('tablib'))), null);
2252 }
2253 if (function_exists('opcache_invalidate')) {
2254 opcache_reset(); // remove the include cache hell !
2255 }
2256 clearstatcache(true);
2257 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
2258 exit;
2259 }
2260 }
2261 //var_dump(GETPOST('tablib'));exit;
2262}
2263if ($dirins && $action == 'generatedoc' && $user->hasRight("modulebuilder", "run")) {
2264 $modulelowercase = strtolower($module);
2265
2266 // Dir for module
2267 $dirofmodule = dol_buildpath($modulelowercase, 0).'/doc';
2268
2269 $FILENAMEDOC = strtolower($module).'.html';
2270
2271 $util = new Utils($db);
2272 $result = $util->generateDoc($module);
2273
2274 if ($result > 0) {
2275 setEventMessages($langs->trans("DocFileGeneratedInto", $dirofmodule), null);
2276 } else {
2277 setEventMessages($util->error, $util->errors, 'errors');
2278 }
2279}
2280
2281if ($dirins && $action == 'generatepackage' && $user->hasRight("modulebuilder", "run")) {
2282 $modulelowercase = strtolower($module);
2283
2284 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2285
2286 // Dir for module
2287 $dir = dol_buildpath($modulelowercase, 0);
2288
2289 // Zip file to build
2290 $FILENAMEZIP = '';
2291
2292 // Load module
2293 dol_include_once($pathtofile);
2294 $class = 'mod'.$module;
2295
2296 if (class_exists($class)) {
2297 try {
2298 $moduleobj = new $class($db);
2299 '@phan-var-force DolibarrMOdules $moduleobj';
2300 } catch (Exception $e) {
2301 $error++;
2302 dol_print_error($db, $e->getMessage());
2303 }
2304 } else {
2305 $error++;
2306 $langs->load("errors");
2307 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2308 exit;
2309 }
2310
2311 $arrayversion = explode('.', $moduleobj->version, 3);
2312 if (count($arrayversion)) {
2313 $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : '.'.$arrayversion[2]).'.zip';
2314
2315 $dirofmodule = dol_buildpath($modulelowercase, 0).'/bin';
2316 $outputfilezip = $dirofmodule.'/'.$FILENAMEZIP;
2317 if ($dirofmodule) {
2318 if (!dol_is_dir($dirofmodule)) {
2319 dol_mkdir($dirofmodule);
2320 }
2321 // Note: We exclude /bin/ to not include the already generated zip
2322 $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase);
2323 } else {
2324 $result = -1;
2325 }
2326
2327 if ($result > 0) {
2328 setEventMessages($langs->trans("ZipFileGeneratedInto", $outputfilezip), null);
2329 } else {
2330 $error++;
2331 $langs->load("errors");
2332 setEventMessages($langs->trans("ErrorFailToGenerateFile", $outputfilezip), null, 'errors');
2333 }
2334 } else {
2335 $error++;
2336 $langs->load("errors");
2337 setEventMessages($langs->trans("ErrorCheckVersionIsDefined"), null, 'errors');
2338 }
2339}
2340
2341// Add permission
2342if ($dirins && $action == 'addright' && !empty($module) && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
2343 $error = 0;
2344
2345 // load class and check if right exist
2346 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2347 dol_include_once($pathtofile);
2348 $class = 'mod'.$module;
2349 $moduleobj = null;
2350 if (class_exists($class)) {
2351 try {
2352 $moduleobj = new $class($db);
2353 '@phan-var-force DolibarrModules $moduleobj';
2354 } catch (Exception $e) {
2355 $error++;
2356 dol_print_error($db, $e->getMessage());
2357 }
2358 }
2359
2360 // verify information entered
2361 if (!GETPOST('label', 'alpha')) {
2362 $error++;
2363 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2364 }
2365 if (!GETPOST('permissionObj', 'alpha')) {
2366 $error++;
2367 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2368 }
2369
2370 $id = GETPOST('id', 'alpha');
2371 $label = GETPOST('label', 'alpha');
2372 $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2373 $crud = GETPOST('crud', 'alpha');
2374
2375 //check existing object permission
2376 $counter = 0;
2377 $permsForObject = array();
2378 if (is_object($moduleobj)) {
2379 $permissions = $moduleobj->rights;
2380 } else {
2381 $permissions = array();
2382 }
2383 $allObject = array();
2384
2385 $countPerms = count($permissions);
2386
2387 for ($i = 0; $i < $countPerms; $i++) {
2388 if ($permissions[$i][4] == $objectForPerms) {
2389 $counter++;
2390 if (count($permsForObject) < 3) {
2391 $permsForObject[] = $permissions[$i];
2392 }
2393 }
2394 $allObject[] = $permissions[$i][4];
2395 }
2396
2397 // check if label of object already exists
2398 $countPermsObj = count($permsForObject);
2399 for ($j = 0; $j < $countPermsObj; $j++) {
2400 if (in_array($crud, $permsForObject[$j])) {
2401 $error++;
2402 setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($crud), $langs->transnoentities($objectForPerms)), null, 'errors');
2403 }
2404 }
2405
2406 $rightToAdd = array();
2407 if (!$error) {
2408 $key = $countPerms + 1;
2409 //prepare right to add
2410 $rightToAdd = array(
2411 0 => $id,
2412 1 => $label,
2413 4 => $objectForPerms,
2414 5 => $crud
2415 );
2416
2417 if (isModEnabled(strtolower($module))) {
2418 $result = unActivateModule(strtolower($module));
2419 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2420 if ($result) {
2421 setEventMessages($result, null, 'errors');
2422 }
2423 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2424 }
2425 }
2426 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2427 //rewriting all permissions after add a right
2428 $rewrite = checkExistComment($moduledescriptorfile, 1);
2429 if ($rewrite < 0) {
2430 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2431 } else {
2432 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightToAdd, '', '', 1);
2433 setEventMessages($langs->trans('PermissionAddedSuccesfuly'), null);
2434
2435 clearstatcache(true);
2436 if (function_exists('opcache_invalidate')) {
2437 opcache_reset(); // remove the include cache hell !
2438 }
2439 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2440 exit;
2441 }
2442}
2443
2444
2445// Update permission
2446if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright') && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
2447 $error = 0;
2448 // load class and check if right exist
2449 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2450 dol_include_once($pathtofile);
2451 $class = 'mod'.$module;
2452 $moduleobj = null;
2453 if (class_exists($class)) {
2454 try {
2455 $moduleobj = new $class($db);
2456 '@phan-var-force DolibarrModules $moduleobj';
2457 } catch (Exception $e) {
2458 $error++;
2459 dol_print_error($db, $e->getMessage());
2460 }
2461 }
2462 // verify information entered
2463 if (!GETPOST('label', 'alpha')) {
2464 $error++;
2465 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2466 }
2467 if (!GETPOST('permissionObj', 'alpha')) {
2468 $error++;
2469 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2470 }
2471
2472 $label = GETPOST('label', 'alpha');
2473 $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2474 $crud = GETPOST('crud', 'alpha');
2475
2476
2477 if ($label == "Read objects of $module" && $crud != "read") {
2478 $crud = "read";
2479 // $label = "Read objects of $module";
2480 }
2481 if ($label == "Create/Update objects of $module" && $crud != "write") {
2482 $crud = "write";
2483 // $label = "Create/Update objects of $module";
2484 }
2485 if ($label == "Delete objects of $module" && $crud != "delete") {
2486 $crud = "delete";
2487 // $label = "Delete objects of $module";
2488 }
2489
2490 if (is_object($moduleobj)) {
2491 $permissions = $moduleobj->rights;
2492 } else {
2493 $permissions = [];
2494 }
2495 $key = GETPOSTINT('counter') - 1;
2496 //get permission want to delete from permissions array
2497 if (array_key_exists($key, $permissions)) {
2498 $x1 = $permissions[$key][1];
2499 $x2 = $permissions[$key][4];
2500 $x3 = $permissions[$key][5];
2501 } else {
2502 $x1 = null;
2503 $x2 = null;
2504 $x3 = null;
2505 }
2506 //check existing object permission
2507 $counter = 0;
2508 $permsForObject = array();
2509 // $permissions = $moduleobj->rights; // Already fetched above
2510 $firstRight = 0;
2511 $existRight = 0;
2512 $allObject = array();
2513
2514 $countPerms = count($permissions);
2515 for ($i = 0; $i < $countPerms; $i++) {
2516 if ($permissions[$i][4] == $objectForPerms) {
2517 $counter++;
2518 if (count($permsForObject) < 3) {
2519 $permsForObject[] = $permissions[$i];
2520 }
2521 }
2522 $allObject[] = $permissions[$i][4];
2523 }
2524
2525 if ($label != $x1 && $crud != $x3) {
2526 $countPermsObj = count($permsForObject);
2527 for ($j = 0; $j < $countPermsObj; $j++) {
2528 if (in_array($label, $permsForObject[$j])) {
2529 $error++;
2530 setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($label), $langs->transnoentities($objectForPerms)), null, 'errors');
2531 }
2532 }
2533 }
2534
2535 if (!$error) {
2536 if (isModEnabled(strtolower($module))) {
2537 $result = unActivateModule(strtolower($module));
2538 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2539 if ($result) {
2540 setEventMessages($result, null, 'errors');
2541 }
2542 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2543 }
2544
2545 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2546 // rewriting all permissions after update permission needed
2547 $rewrite = checkExistComment($moduledescriptorfile, 1);
2548 if ($rewrite < 0) {
2549 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2550 } else {
2551 $rightUpdated = null; // I not set at this point
2552 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightUpdated, '', '', 2);
2553 setEventMessages($langs->trans('PermissionUpdatedSuccesfuly'), null);
2554 clearstatcache(true);
2555 if (function_exists('opcache_invalidate')) {
2556 opcache_reset(); // remove the include cache hell !
2557 }
2558 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2559 exit;
2560 }
2561 }
2562}
2563// Delete permission
2564if ($dirins && $action == 'confirm_deleteright' && !empty($module) && GETPOSTINT('permskey') && $user->hasRight("modulebuilder", "run")) {
2565 $error = 0;
2566 // load class and check if right exist
2567 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2568 dol_include_once($pathtofile);
2569 $class = 'mod'.$module;
2570 $moduleobj = null;
2571 if (class_exists($class)) {
2572 try {
2573 $moduleobj = new $class($db);
2574 '@phan-var-force DolibarrMOdules $moduleobj';
2575 } catch (Exception $e) {
2576 $error++;
2577 dol_print_error($db, $e->getMessage());
2578 }
2579 }
2580
2581 $permissions = $moduleobj->rights;
2582 $key = GETPOSTINT('permskey') - 1;
2583
2584 if (!$error) {
2585 // check if module is enabled
2586 if (isModEnabled(strtolower($module))) {
2587 $result = unActivateModule(strtolower($module));
2588 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2589 if ($result) {
2590 setEventMessages($result, null, 'errors');
2591 }
2592 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2593 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2594 exit;
2595 }
2596
2597 // rewriting all permissions
2598 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2599 $rewrite = checkExistComment($moduledescriptorfile, 1);
2600 if ($rewrite < 0) {
2601 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2602 } else {
2603 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, null, '', '', 0);
2604 setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null);
2605
2606 clearstatcache(true);
2607 if (function_exists('opcache_invalidate')) {
2608 opcache_reset(); // remove the include cache hell !
2609 }
2610
2611 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2612 exit;
2613 }
2614 }
2615}
2616// Save file
2617if ($action == 'savefile' && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
2618 $relofcustom = basename($dirins);
2619
2620 if ($relofcustom) {
2621 // Check that relative path ($file) start with name 'custom'
2622 if (!preg_match('/^'.$relofcustom.'/', $file)) {
2623 $file = $relofcustom.'/'.$file;
2624 }
2625
2626 $pathoffile = dol_buildpath($file, 0);
2627 $pathoffilebackup = dol_buildpath($file.'.back', 0);
2628
2629 // Save old version
2630 if (dol_is_file($pathoffile)) {
2631 dol_copy($pathoffile, $pathoffilebackup, '0', 1);
2632 }
2633
2634 $check = 'restricthtml';
2635 $srclang = dol_mimetype($pathoffile, '', 3);
2636 if ($srclang == 'md') {
2637 $check = 'restricthtml';
2638 }
2639 if ($srclang == 'lang') {
2640 $check = 'restricthtml';
2641 }
2642 if ($srclang == 'php') {
2643 $check = 'none';
2644 }
2645
2646 $content = GETPOST('editfilecontent', $check);
2647
2648 // Save file on disk
2649 if ($content) {
2650 dol_delete_file($pathoffile);
2651 $result = file_put_contents($pathoffile, $content);
2652 if ($result) {
2653 dolChmod($pathoffile, $newmask);
2654
2655 setEventMessages($langs->trans("FileSaved"), null);
2656 } else {
2657 setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
2658 }
2659 } else {
2660 setEventMessages($langs->trans("ContentCantBeEmpty"), null, 'errors');
2661 //$action='editfile';
2662 $error++;
2663 }
2664 }
2665}
2666
2667// Enable module
2668if ($action == 'set' && $user->admin && $user->hasRight("modulebuilder", "run")) {
2669 $param = '';
2670 if ($module) {
2671 $param .= '&module='.urlencode($module);
2672 }
2673 if ($tab) {
2674 $param .= '&tab='.urlencode($tab);
2675 }
2676 if ($tabobj) {
2677 $param .= '&tabobj='.urlencode($tabobj);
2678 }
2679
2680 $value = GETPOST('value', 'alpha');
2681 $resarray = activateModule($value);
2682 if (!empty($resarray['errors'])) {
2683 setEventMessages('', $resarray['errors'], 'errors');
2684 } else {
2685 //var_dump($resarray);exit;
2686 if ($resarray['nbperms'] > 0) {
2687 $tmpsql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1";
2688 $resqltmp = $db->query($tmpsql);
2689 if ($resqltmp) {
2690 $obj = $db->fetch_object($resqltmp);
2691 //var_dump($obj->nb);exit;
2692 if ($obj && $obj->nb > 1) {
2693 $msg = $langs->trans('ModuleEnabledAdminMustCheckRights');
2694 setEventMessages($msg, null, 'warnings');
2695 }
2696 } else {
2697 dol_print_error($db);
2698 }
2699 }
2700 }
2701 header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2702 exit;
2703}
2704
2705// Disable module
2706if ($action == 'reset' && $user->admin && $user->hasRight("modulebuilder", "run")) {
2707 $param = '';
2708 if ($module) {
2709 $param .= '&module='.urlencode($module);
2710 }
2711 if ($tab) {
2712 $param .= '&tab='.urlencode($tab);
2713 }
2714 if ($tabobj) {
2715 $param .= '&tabobj='.urlencode($tabobj);
2716 }
2717
2718 $value = GETPOST('value', 'alpha');
2719 $result = unActivateModule($value);
2720 if ($result) {
2721 setEventMessages($result, null, 'errors');
2722 }
2723 header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2724 exit;
2725}
2726
2727// delete menu
2728if ($dirins && $action == 'confirm_deletemenu' && GETPOSTINT('menukey') && $user->hasRight("modulebuilder", "run")) {
2729 // check if module is enabled
2730 if (isModEnabled(strtolower($module))) {
2731 $result = unActivateModule(strtolower($module));
2732 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2733 if ($result) {
2734 setEventMessages($result, null, 'errors');
2735 }
2736 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2737 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2738 exit;
2739 }
2740 // load class and check if menu exist
2741 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2742 dol_include_once($pathtofile);
2743 $class = 'mod'.$module;
2744 $moduleobj = null;
2745 if (class_exists($class)) {
2746 try {
2747 $moduleobj = new $class($db);
2748 '@phan-var-force DolibarrMOdules $moduleobj';
2749 } catch (Exception $e) {
2750 $error++;
2751 dol_print_error($db, $e->getMessage());
2752 }
2753 }
2754 // get all objects and convert value to lower case for compare
2755 $dir = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2756 $destdir = $dir.'/'.strtolower($module);
2757 $objects = dolGetListOfObjectClasses($destdir);
2758 $result = array_map('strtolower', $objects);
2759
2760 $menus = $moduleobj->menu;
2761 $key = GETPOSTINT('menukey');
2762 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2763
2764 $checkcomment = checkExistComment($moduledescriptorfile, 0);
2765 if ($checkcomment < 0) {
2766 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
2767 } else {
2768 if ($menus[$key]['fk_menu'] === 'fk_mainmenu='.strtolower($module)) {
2769 if (in_array(strtolower($menus[$key]['leftmenu']), $result)) {
2770 reWriteAllMenus($moduledescriptorfile, $menus, $menus[$key]['leftmenu'], $key, -1);
2771 } else {
2772 reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
2773 }
2774 } else {
2775 reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
2776 }
2777
2778 clearstatcache(true);
2779 if (function_exists('opcache_invalidate')) {
2780 opcache_reset(); // remove the include cache hell !
2781 }
2782
2783 setEventMessages($langs->trans('MenuDeletedSuccessfuly'), null);
2784 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2785 exit;
2786 }
2787}
2788
2789// Add menu in module without initial object
2790if ($dirins && $action == 'addmenu' && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
2791 // check if module is enabled
2792 if (isModEnabled(strtolower($module))) {
2793 $result = unActivateModule(strtolower($module));
2794 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2795 if ($result) {
2796 setEventMessages($result, null, 'errors');
2797 }
2798 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2799 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2800 exit;
2801 }
2802 $error = 0;
2803
2804 // load class and check if right exist
2805 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2806 dol_include_once($pathtofile);
2807 $class = 'mod'.$module;
2808 $moduleobj = null;
2809 if (class_exists($class)) {
2810 try {
2811 $moduleobj = new $class($db);
2812 '@phan-var-force DolibarrMOdules $moduleobj';
2813 } catch (Exception $e) {
2814 $error++;
2815 dol_print_error($db, $e->getMessage());
2816 }
2817 }
2818 // get all menus
2819 $menus = $moduleobj->menu;
2820
2821 //verify fields required
2822 if (!GETPOST('type', 'alpha')) {
2823 $error++;
2824 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
2825 }
2826 if (!GETPOST('titre', 'alpha')) {
2827 $error++;
2828 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Title")), null, 'errors');
2829 }
2830 if (!GETPOST('user', 'alpha')) {
2831 $error++;
2832 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("DetailUser")), null, 'errors');
2833 }
2834 if (!GETPOST('url', 'alpha')) {
2835 $error++;
2836 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Url")), null, 'errors');
2837 }
2838 if (!empty(GETPOST('target'))) {
2839 $targets = array('_blank','_self','_parent','_top','');
2840 if (!in_array(GETPOST('target'), $targets)) {
2841 $error++;
2842 setEventMessages($langs->trans("ErrorFieldValue", $langs->transnoentities("target")), null, 'errors');
2843 }
2844 }
2845
2846
2847 // check if title or url already exist in menus
2848
2849 foreach ($menus as $menu) {
2850 if (!empty(GETPOST('url')) && GETPOST('url') == $menu['url']) {
2851 $error++;
2852 setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("url")), null, 'errors');
2853 break;
2854 }
2855 if (strtolower(GETPOST('titre')) == strtolower($menu['titre'])) {
2856 $error++;
2857 setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("titre")), null, 'errors');
2858 break;
2859 }
2860 }
2861
2862 if (GETPOST('type', 'alpha') == 'left' && !empty(GETPOST('lefmenu', 'alpha'))) {
2863 if (!str_contains(GETPOST('leftmenu'), strtolower($module))) {
2864 $error++;
2865 setEventMessages($langs->trans("WarningFieldsMustContains", $langs->transnoentities("LeftmenuId")), null, 'errors');
2866 }
2867 }
2868 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2869 $destdir = $dirins.'/'.strtolower($module);
2870 $objects = dolGetListOfObjectClasses($destdir);
2871
2872 if (GETPOST('type', 'alpha') == 'left') {
2873 if (empty(GETPOST('leftmenu')) && count($objects) > 0) {
2874 $error++;
2875 setEventMessages($langs->trans("ErrorCoherenceMenu", $langs->transnoentities("LeftmenuId"), $langs->transnoentities("type")), null, 'errors');
2876 }
2877 }
2878 if (GETPOST('type', 'alpha') == 'top') {
2879 $error++;
2880 setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
2881 }
2882
2883 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2884 if (!$error) {
2885 //stock forms in array
2886 $menuToAdd = array(
2887 'fk_menu' => GETPOST('fk_menu', 'alpha'),
2888 'type' => GETPOST('type', 'alpha'),
2889 'titre' => ucfirst(GETPOST('titre', 'alpha')),
2890 'prefix' => '',
2891 'mainmenu' => GETPOST('mainmenu', 'alpha'),
2892 'leftmenu' => GETPOST('leftmenu', 'alpha'),
2893 'url' => GETPOST('url', 'alpha'),
2894 'langs' => strtolower($module)."@".strtolower($module),
2895 'position' => '',
2896 'enabled' => GETPOST('enabled', 'alpha'),
2897 'perms' => '$user->hasRight("'.strtolower($module).'", "'.GETPOST('objects', 'alpha').'", "'.GETPOST('perms', 'alpha').'")',
2898 'target' => GETPOST('target', 'alpha'),
2899 'user' => GETPOST('user', 'alpha'),
2900 );
2901
2902 if (GETPOST('type') == 'left') {
2903 unset($menuToAdd['prefix']);
2904 if (empty(GETPOST('fk_menu'))) {
2905 $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha');
2906 } else {
2907 $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha').',fk_leftmenu='.GETPOST('fk_menu');
2908 }
2909 }
2910 if (GETPOST('enabled') == '1') {
2911 $menuToAdd['enabled'] = 'isModEnabled("'.strtolower($module).'")';
2912 } else {
2913 $menuToAdd['enabled'] = "0";
2914 }
2915 if (empty(GETPOST('objects'))) {
2916 $menuToAdd['perms'] = '1';
2917 }
2918
2919 $checkcomment = checkExistComment($moduledescriptorfile, 0);
2920 if ($checkcomment < 0) {
2921 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
2922 } else {
2923 // Write all menus
2924 $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuToAdd, null, 1);
2925
2926 clearstatcache(true);
2927 if (function_exists('opcache_invalidate')) {
2928 opcache_reset();
2929 }
2930 /*if ($result < 0) {
2931 setEventMessages($langs->trans('ErrorMenuExistValue'), null, 'errors');
2932 header("Location: ".$_SERVER["PHP_SELF"].'?action=editmenu&token='.newToken().'&menukey='.urlencode($key+1).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.($key+1));
2933 exit;
2934 }*/
2935
2936 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2937 setEventMessages($langs->trans('MenuAddedSuccesfuly'), null);
2938 exit;
2939 }
2940 }
2941}
2942
2943// Modify a menu entry
2944if ($dirins && $action == "update_menu" && GETPOSTINT('menukey') && GETPOST('tabobj') && $user->hasRight("modulebuilder", "run")) {
2945 $objectname = GETPOST('tabobj');
2946 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2947 $destdir = $dirins.'/'.strtolower($module);
2948 $objects = dolGetListOfObjectClasses($destdir);
2949
2950 if (empty($cancel)) {
2951 if (isModEnabled(strtolower($module))) {
2952 $result = unActivateModule(strtolower($module));
2953 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2954 if ($result) {
2955 setEventMessages($result, null, 'errors');
2956 }
2957 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2958 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2959 exit;
2960 }
2961 $error = 0;
2962 // for loading class and the menu wants to modify
2963 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2964 dol_include_once($pathtofile);
2965 $class = 'mod'.$module;
2966 $moduleobj = null;
2967 if (class_exists($class)) {
2968 try {
2969 $moduleobj = new $class($db);
2970 '@phan-var-force DolibarrMOdules $moduleobj';
2971 } catch (Exception $e) {
2972 $error++;
2973 dol_print_error($db, $e->getMessage());
2974 }
2975 }
2976 $menus = $moduleobj->menu;
2977 $key = GETPOSTINT('menukey') - 1;
2978
2979 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2980 //stock forms in array
2981 $menuModify = array(
2982 'fk_menu' => GETPOST('fk_menu', 'alpha'),
2983 'type' => GETPOST('type', 'alpha'),
2984 'titre' => ucfirst(GETPOST('titre', 'alpha')),
2985 'mainmenu' => GETPOST('mainmenu', 'alpha'),
2986 'leftmenu' => $menus[$key]['leftmenu'],
2987 'url' => GETPOST('url', 'alpha'),
2988 'langs' => strtolower($module)."@".strtolower($module),
2989 'position' => '',
2990 'enabled' => GETPOST('enabled', 'alpha'),
2991 'perms' => GETPOST('perms', 'alpha'),
2992 'target' => GETPOST('target', 'alpha'),
2993 'user' => GETPOST('user', 'alpha'),
2994 );
2995 if (!empty(GETPOST('fk_menu')) && GETPOST('fk_menu') != $menus[$key]['fk_menu']) {
2996 $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu').',fk_leftmenu='.GETPOST('fk_menu');
2997 } elseif (GETPOST('fk_menu') == $menus[$key]['fk_menu']) {
2998 $menuModify['fk_menu'] = $menus[$key]['fk_menu'];
2999 } else {
3000 $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu');
3001 }
3002 if ($menuModify['enabled'] === '') {
3003 $menuModify['enabled'] = '1';
3004 }
3005 if ($menuModify['perms'] === '') {
3006 $menuModify['perms'] = '1';
3007 }
3008
3009 if (GETPOST('type', 'alpha') == 'top') {
3010 $error++;
3011 setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
3012 }
3013
3014 if (!$error) {
3015 //update menu
3016 $checkComment = checkExistComment($moduledescriptorfile, 0);
3017
3018 if ($checkComment < 0) {
3019 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
3020 } else {
3021 // Write all menus
3022 $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuModify, $key, 2);
3023
3024 clearstatcache(true);
3025 if (function_exists('opcache_invalidate')) {
3026 opcache_reset();
3027 }
3028
3029 if ($result < 0) {
3030 setEventMessages($langs->trans('ErrorMenuExistValue'), null, 'errors');
3031 //var_dump($_SESSION);exit;
3032 header("Location: ".$_SERVER["PHP_SELF"].'?action=editmenu&token='.newToken().'&menukey='.urlencode((string) ($key + 1)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'&tabobj='.($key + 1));
3033 exit;
3034 }
3035
3036 setEventMessages($langs->trans('MenuUpdatedSuccessfuly'), null);
3037 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3038 exit;
3039 }
3040 }
3041 } else {
3042 $_POST['type'] = ''; // TODO Use a var here and later
3043 $_POST['titre'] = '';
3044 $_POST['fk_menu'] = '';
3045 $_POST['leftmenu'] = '';
3046 $_POST['url'] = '';
3047 }
3048}
3049
3050// update properties description of module
3051if ($dirins && $action == "update_props_module" && !empty(GETPOST('keydescription', 'alpha')) && empty($cancel) && $user->hasRight("modulebuilder", "run")) {
3052 if (isModEnabled(strtolower($module))) {
3053 $result = unActivateModule(strtolower($module));
3054 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
3055 if ($result) {
3056 setEventMessages($result, null, 'errors');
3057 }
3058 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
3059 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3060 exit;
3061 }
3062 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3063 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
3064 $modulelogfile = $dirins.'/'.strtolower($module).'/ChangeLog.md';
3065
3066 dol_include_once($pathtofile);
3067
3068 $class = 'mod'.$module;
3069 $moduleobj = null;
3070 if (class_exists($class)) {
3071 try {
3072 $moduleobj = new $class($db);
3073 '@phan-var-force DolibarrMOdules $moduleobj';
3074 } catch (Exception $e) {
3075 $error++;
3076 dol_print_error($db, $e->getMessage());
3077 }
3078 }
3079
3080 $keydescription = GETPOST('keydescription', 'alpha');
3081 switch ($keydescription) {
3082 case 'desc':
3083 $propertyToUpdate = 'description';
3084 break;
3085 case 'version':
3086 case 'family':
3087 case 'picto':
3088 case 'editor_name':
3089 case 'editor_url':
3090 $propertyToUpdate = $keydescription;
3091 break;
3092 default:
3093 $error = GETPOST('keydescription');
3094 break;
3095 }
3096
3097 if (isset($propertyToUpdate) && !empty(GETPOST('propsmodule'))) {
3098 $newValue = GETPOST('propsmodule');
3099 $lineToReplace = "\t\t\$this->$propertyToUpdate = ";
3100 $newLine = "\t\t\$this->$propertyToUpdate = '$newValue';\n";
3101
3102 //for change version in log file
3103 if ($propertyToUpdate === 'version') {
3104 dolReplaceInFile($modulelogfile, array("## ".$moduleobj->$propertyToUpdate => $newValue));
3105 }
3106
3107 $fileLines = file($moduledescriptorfile);
3108 foreach ($fileLines as &$line) {
3109 if (strpos($line, $lineToReplace) === 0) {
3110 dolReplaceInFile($moduledescriptorfile, array($line => $newLine));
3111 break;
3112 }
3113 }
3114
3115 clearstatcache(true);
3116 if (function_exists('opcache_invalidate')) {
3117 opcache_reset();
3118 }
3119 setEventMessages($langs->trans('PropertyModuleUpdated', $propertyToUpdate), null);
3120 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=description&module='.$module);
3121 exit;
3122 }
3123}
3124
3125
3126/*
3127 * View
3128 */
3129
3130$form = new Form($db);
3131$formadmin = new FormAdmin($db);
3132
3133// Set dir where external modules are installed
3134if (!dol_is_dir($dirins)) {
3135 dol_mkdir($dirins);
3136}
3137$dirins_ok = (dol_is_dir($dirins));
3138
3139$help_url = '';
3140$morejs = array(
3141 '/includes/ace/src/ace.js',
3142 '/includes/ace/src/ext-statusbar.js',
3143 '/includes/ace/src/ext-language_tools.js',
3144 //'/includes/ace/src/ext-chromevox.js'
3145);
3146$morecss = array();
3147
3148llxHeader('', $langs->trans("ModuleBuilder"), $help_url, '', 0, 0, $morejs, $morecss, '', 'classforhorizontalscrolloftabs');
3149
3150
3151$text = $langs->trans("ModuleBuilder");
3152
3153print load_fiche_titre($text, '', 'title_setup');
3154
3155print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModuleBuilderDesc", 'https://wiki.dolibarr.org/index.php/Module_development#Create_your_module').'</span>';
3156print '<br class="hideonsmartphone">';
3157
3158//print $textforlistofdirs;
3159//print '<br>';
3160
3161
3162
3163$message = '';
3164if (!$dirins) {
3165 $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
3166 $allowfromweb = -1;
3167} else {
3168 if ($dirins_ok) {
3169 if (!is_writable(dol_osencode($dirins))) {
3170 $langs->load("errors");
3171 $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins));
3172 $allowfromweb = 0;
3173 }
3174 } else {
3175 $message = info_admin($langs->trans("NotExistsDirect", $dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
3176 $allowfromweb = 0;
3177 }
3178}
3179if ($message) {
3180 print $message;
3181}
3182
3183//print $langs->trans("ModuleBuilderDesc3", count($listofmodules), $FILEFLAG).'<br>';
3184$infomodulesfound = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', $langs->trans("ModuleBuilderDesc3", count($listofmodules)).'<br><br>'.$langs->trans("ModuleBuilderDesc4", $FILEFLAG).'<br>'.$textforlistofdirs).'</div>';
3185
3186
3187
3188$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
3189$allowonlineinstall = true;
3190if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
3191 $allowonlineinstall = false;
3192}
3193if (empty($allowonlineinstall)) {
3194 if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
3195 // Show clean message
3196 $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'));
3197 } else {
3198 // Show technical message
3199 $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'), 0, 0, '1', 'warning');
3200 }
3201
3202 print $message;
3203
3204 llxFooter();
3205 exit(0);
3206}
3207
3208
3209// Load module descriptor
3210$error = 0;
3211$moduleobj = null;
3212
3213
3214if (!empty($module) && $module != 'initmodule' && $module != 'deletemodule') {
3215 $modulelowercase = strtolower($module);
3216 $loadclasserrormessage = '';
3217
3218 // Load module
3219 try {
3220 $fullpathdirtodescriptor = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3221
3222 //throw(new Exception());
3223 dol_include_once($fullpathdirtodescriptor);
3224
3225 $class = 'mod'.$module;
3226 } catch (Throwable $e) { // This is called in PHP 7 only (includes Error and Exception)
3227 $loadclasserrormessage = $e->getMessage()."<br>\n";
3228 $loadclasserrormessage .= 'File: '.$e->getFile()."<br>\n";
3229 $loadclasserrormessage .= 'Line: '.$e->getLine()."<br>\n";
3230 }
3231
3232 $moduleobj = null;
3233 if (class_exists($class)) {
3234 try {
3235 $moduleobj = new $class($db);
3236 '@phan-var-force DolibarrMOdules $moduleobj';
3237 } catch (Exception $e) {
3238 $error++;
3239 print $e->getMessage();
3240 }
3241 } else {
3242 if (empty($forceddirread)) {
3243 $error++;
3244 }
3245 $langs->load("errors");
3246 print '<!-- ErrorFailedToLoadModuleDescriptorForXXX -->';
3247 print img_warning('').' '.$langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
3248 print $loadclasserrormessage;
3249 }
3250}
3251
3252print '<br>';
3253
3254
3255// Tabs for all modules
3256$head = array();
3257$h = 0;
3258
3259$head[$h][0] = $_SERVER["PHP_SELF"].'?module=initmodule';
3260$head[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewModule").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
3261$head[$h][2] = 'initmodule';
3262$h++;
3263
3264$linktoenabledisable = '';
3265
3266if (is_array($listofmodules) && count($listofmodules) > 0) {
3267 // Define $linktoenabledisable
3268 $modulelowercase = strtolower($module);
3269
3270 $param = '';
3271 if ($tab) {
3272 $param .= '&tab='.urlencode($tab);
3273 }
3274 if ($module) {
3275 $param .= '&module='.urlencode($module);
3276 }
3277 if ($tabobj) {
3278 $param .= '&tabobj='.urlencode($tabobj);
3279 }
3280
3281 $urltomodulesetup = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?search_keyword='.urlencode($module).'">'.$langs->trans('Home').'-'.$langs->trans("Setup").'-'.$langs->trans("Modules").'</a>';
3282
3283 // Define $linktoenabledisable to show after module title
3284 if (isModEnabled($modulelowercase)) { // If module is already activated
3285 $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=reset&token='.newToken().'&value=mod'.$module.$param.'">';
3286 $linktoenabledisable .= img_picto($langs->trans("Activated"), 'switch_on', '', 0, 0, 0, '', '', 1);
3287 $linktoenabledisable .= '</a>';
3288
3289 $linktoenabledisable .= $form->textwithpicto('', $langs->trans("Warning").' : '.$langs->trans("ModuleIsLive"), -1, 'warning');
3290
3291 $objMod = $moduleobj;
3292 $backtourlparam = '';
3293 $backtourlparam .= ($backtourlparam ? '&' : '?').'module='.$module; // No urlencode here, done later
3294 if ($tab) {
3295 $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later
3296 }
3297 $backtourl = $_SERVER["PHP_SELF"].$backtourlparam;
3298
3299 $regs = array();
3300 if (is_array($objMod->config_page_url)) {
3301 $i = 0;
3302 foreach ($objMod->config_page_url as $page) {
3303 $urlpage = $page;
3304 if ($i++) {
3305 $linktoenabledisable .= ' <a href="'.$urlpage.'" title="'.$langs->trans($page).'">'.img_picto(ucfirst($page), "setup").'</a>';
3306 // print '<a href="'.$page.'">'.ucfirst($page).'</a>&nbsp;';
3307 } else {
3308 if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) {
3309 $urltouse = dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1);
3310 $linktoenabledisable .= ' <a href="'.$urltouse.(preg_match('/\?/', $urltouse) ? '&' : '?').'save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 8px"').'</a>';
3311 } else {
3312 // Case standard admin page (not a page provided by the
3313 // module but a page provided by dolibarr)
3314 $urltouse = DOL_URL_ROOT.'/admin/'.$urlpage;
3315 $linktoenabledisable .= ' <a href="'.$urltouse.(preg_match('/\?/', $urltouse) ? '&' : '?').'save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 8px"').'</a>';
3316 }
3317 }
3318 }
3319 } elseif (preg_match('/^([^@]+)@([^@]+)$/i', $objMod->config_page_url, $regs)) {
3320 $linktoenabledisable .= ' &nbsp; <a href="'.dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1).'?save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 8px"').'</a>';
3321 }
3322 } else {
3323 if (is_object($moduleobj)) {
3324 $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=set&token='.newToken().'&value=mod'.$module.$param.'">';
3325 $linktoenabledisable .= img_picto($langs->trans("ModuleIsNotActive", $urltomodulesetup), 'switch_off', 'style="padding-right: 8px"', 0, 0, 0, '', 'classfortooltip', 1);
3326 $linktoenabledisable .= "</a>\n";
3327 }
3328 }
3329
3330 // Loop to show tab of each module
3331 foreach ($listofmodules as $tmpmodule => $tmpmodulearray) {
3332 $head[$h][0] = $_SERVER["PHP_SELF"].'?module='.$tmpmodulearray['modulenamewithcase'].($forceddirread ? '@'.$dirread : '');
3333 $head[$h][1] = $tmpmodulearray['modulenamewithcase'];
3334 $head[$h][2] = $tmpmodulearray['modulenamewithcase'];
3335
3336 if ($tmpmodulearray['modulenamewithcase'] == $module) {
3337 $head[$h][4] = '<span class="inline-block">'.$linktoenabledisable.'</span>';
3338 }
3339
3340 $h++;
3341 }
3342}
3343
3344$head[$h][0] = $_SERVER["PHP_SELF"].'?module=deletemodule';
3345$head[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
3346$head[$h][2] = 'deletemodule';
3347$h++;
3348
3349
3350print dol_get_fiche_head($head, $module, '', -1, '', 0, $infomodulesfound, '', 8); // Modules
3351
3352if ($module == 'initmodule') {
3353 // New module
3354 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3355 print '<input type="hidden" name="token" value="'.newToken().'">';
3356 print '<input type="hidden" name="action" value="initmodule">';
3357 print '<input type="hidden" name="module" value="initmodule">';
3358
3359 //print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc2", 'conf/conf.php', $newdircustom).'</span><br>';
3360 print '<br>';
3361
3362 print '<div class="tagtable">';
3363
3364 print '<div class="tagtr"><div class="tagtd paddingright">';
3365 print '<span class="opacitymedium">'.$langs->trans("IdModule").'</span>';
3366 print '</div><div class="tagtd">';
3367 print '<input type="text" name="idmodule" class="width75" value="500000" placeholder="'.dol_escape_htmltag($langs->trans("IdModule")).'">';
3368 print '<span class="opacitymedium">';
3369 print ' &nbsp; (';
3370 print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
3371 print ' - ';
3372 print '<a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>';
3373 print ')';
3374 print '</span>';
3375 print '</div></div>';
3376
3377 print '<div class="tagtr"><div class="tagtd paddingright">';
3378 print '<span class="opacitymedium fieldrequired">'.$langs->trans("ModuleName").'</span>';
3379 print '</div><div class="tagtd">';
3380 print '<input type="text" name="modulename" value="'.dol_escape_htmltag($modulename).'" autofocus>';
3381 print ' '.$form->textwithpicto('', $langs->trans("EnterNameOfModuleDesc"));
3382 print '</div></div>';
3383
3384 print '<div class="tagtr"><div class="tagtd paddingright">';
3385 print '<span class="opacitymedium">'.$langs->trans("Description").'</span>';
3386 print '</div><div class="tagtd">';
3387 print '<input type="text" name="description" value="" class="minwidth500"><br>';
3388 print '</div></div>';
3389
3390 print '<div class="tagtr"><div class="tagtd paddingright">';
3391 print '<span class="opacitymedium">'.$langs->trans("Version").'</span>';
3392 print '</div><div class="tagtd">';
3393 print '<input type="text" name="version" class="width75" value="'.(GETPOSTISSET('version') ? GETPOST('version') : getDolGlobalString('MODULEBUILDER_SPECIFIC_VERSION', '1.0')).'" placeholder="'.dol_escape_htmltag($langs->trans("Version")).'">';
3394 print '</div></div>';
3395
3396 print '<div class="tagtr"><div class="tagtd paddingright">';
3397 print '<span class="opacitymedium">'.$langs->trans("Family").'</span>';
3398 print '</div><div class="tagtd">';
3399 print '<select name="family" id="family" class="minwidth400">';
3400 $arrayoffamilies = array(
3401 'hr' => "ModuleFamilyHr",
3402 'crm' => "ModuleFamilyCrm",
3403 'srm' => "ModuleFamilySrm",
3404 'financial' => 'ModuleFamilyFinancial',
3405 'products' => 'ModuleFamilyProducts',
3406 'projects' => 'ModuleFamilyProjects',
3407 'ecm' => 'ModuleFamilyECM',
3408 'technic' => 'ModuleFamilyTechnic',
3409 'portal' => 'ModuleFamilyPortal',
3410 'interface' => 'ModuleFamilyInterface',
3411 'base' => 'ModuleFamilyBase',
3412 'other' => 'ModuleFamilyOther'
3413 );
3414 foreach ($arrayoffamilies as $key => $value) {
3415 print '<option value="hr"'.($key == getDolGlobalString('MODULEBUILDER_SPECIFIC_FAMILY', 'other') ? ' selected="selected"' : '').' data-html="'.dol_escape_htmltag($langs->trans($value).' <span class="opacitymedium">- '.$key.'</span>').'">'.$langs->trans($value).'</option>';
3416 }
3417 print '</select>';
3418 print ajax_combobox("family");
3419 print '</div></div>';
3420
3421 print '<div class="tagtr"><div class="tagtd paddingright">';
3422 print '<span class="opacitymedium">'.$langs->trans("Picto").'</span>';
3423 print '</div><div class="tagtd">';
3424 print '<input type="text" name="idpicto" value="'.(GETPOSTISSET('idpicto') ? GETPOST('idpicto') : getDolGlobalString('MODULEBUILDER_DEFAULTPICTO', 'fa-file-o')).'" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
3425 print $form->textwithpicto('', $langs->trans("Example").': fa-file-o, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
3426 print '</div></div>';
3427
3428 print '<div class="tagtr"><div class="tagtd paddingright">';
3429 print '<span class="opacitymedium">'.$langs->trans("EditorName").'</span>';
3430 print '</div><div class="tagtd">';
3431 print '<input type="text" name="editorname" value="'.(GETPOSTISSET('editorname') ? GETPOST('editorname') : getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_NAME', $mysoc->name)).'" placeholder="'.dol_escape_htmltag($langs->trans("EditorName")).'"><br>';
3432 print '</div></div>';
3433
3434 print '<div class="tagtr"><div class="tagtd paddingright">';
3435 print '<span class="opacitymedium">'.$langs->trans("EditorUrl").'</span>';
3436 print '</div><div class="tagtd">';
3437 print '<input type="text" name="editorurl" value="'.(GETPOSTISSET('editorurl') ? GETPOST('editorurl') : getDolGlobalString('MODULEBUILDER_SPECIFIC_EDITOR_URL', $mysoc->url)).'" placeholder="'.dol_escape_htmltag($langs->trans("EditorUrl")).'"><br>';
3438 print '</div></div>';
3439
3440 print '<br><input type="submit" class="button" name="create" value="'.dol_escape_htmltag($langs->trans("Create")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3441 print '</form>';
3442} elseif ($module == 'deletemodule') {
3443 print '<!-- Form to init a module -->'."\n";
3444 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="delete">';
3445 print '<input type="hidden" name="token" value="'.newToken().'">';
3446 print '<input type="hidden" name="action" value="confirm_deletemodule">';
3447 print '<input type="hidden" name="module" value="deletemodule">';
3448
3449 print $langs->trans("EnterNameOfModuleToDeleteDesc").'<br><br>';
3450
3451 print '<input type="text" name="module" placeholder="'.dol_escape_htmltag($langs->trans("ModuleKey")).'" value="" autofocus>';
3452 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Delete").'"'.($dirins ? '' : ' disabled="disabled"').'>';
3453 print '</form>';
3454} elseif (!empty($module)) {
3455 // Tabs for module
3456 if (!$error) {
3457 $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
3458 $destdir = $dirread.'/'.strtolower($module);
3459 $objects = dolGetListOfObjectClasses($destdir);
3460 $diroflang = dol_buildpath($modulelowercase, 0)."/langs";
3461 $countLangs = countItemsInDirectory($diroflang, 2);
3462 $countDictionaries = (!empty($moduleobj->dictionaries) ? count($moduleobj->dictionaries['tabname']) : 0);
3463 $countRights = count($moduleobj->rights);
3464 $countMenus = count($moduleobj->menu);
3465 $countTriggers = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/triggers");
3466 $countWidgets = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/boxes");
3467 $countEmailingSelectors = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/modules/mailings");
3468 $countCss = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/css");
3469 $countJs = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/js");
3470 $countCLI = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/scripts");
3471 $hasDoc = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/doc");
3472 //var_dump($moduleobj->dictionaries);exit;
3473 $head2 = array();
3474 $h = 0;
3475
3476 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=description&module='.$module.($forceddirread ? '@'.$dirread : '');
3477 $head2[$h][1] = $langs->trans("Description");
3478 $head2[$h][2] = 'description';
3479 $h++;
3480
3481 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '');
3482 $head2[$h][1] = ((!is_array($objects) || count($objects) <= 0) ? $langs->trans("Objects") : $langs->trans("Objects").'<span class="marginleftonlyshort badge">'.count($objects)."</span>");
3483 $head2[$h][2] = 'objects';
3484 $h++;
3485
3486 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=languages&module='.$module.($forceddirread ? '@'.$dirread : '');
3487 $head2[$h][1] = ($countLangs <= 0 ? $langs->trans("Languages") : $langs->trans("Languages").'<span class="marginleftonlyshort badge">'.$countLangs."</span>");
3488 $head2[$h][2] = 'languages';
3489 $h++;
3490
3491 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '');
3492 $head2[$h][1] = ($countDictionaries == 0 ? $langs->trans("Dictionaries") : $langs->trans('Dictionaries').'<span class="marginleftonlyshort badge">'.$countDictionaries."</span>");
3493 $head2[$h][2] = 'dictionaries';
3494 $h++;
3495
3496 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=permissions&module='.$module.($forceddirread ? '@'.$dirread : '');
3497 $head2[$h][1] = ($countRights <= 0 ? $langs->trans("Permissions") : $langs->trans("Permissions").'<span class="marginleftonlyshort badge">'.$countRights."</span>");
3498 $head2[$h][2] = 'permissions';
3499 $h++;
3500
3501 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=tabs&module='.$module.($forceddirread ? '@'.$dirread : '');
3502 $head2[$h][1] = $langs->trans("Tabs");
3503 $head2[$h][2] = 'tabs';
3504 $h++;
3505
3506 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=menus&module='.$module.($forceddirread ? '@'.$dirread : '');
3507 $head2[$h][1] = ($countMenus <= 0 ? $langs->trans("Menus") : $langs->trans("Menus").'<span class="marginleftonlyshort badge">'.$countMenus."</span>");
3508 $head2[$h][2] = 'menus';
3509 $h++;
3510
3511 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=hooks&module='.$module.($forceddirread ? '@'.$dirread : '');
3512 $head2[$h][1] = $langs->trans("Hooks");
3513 $head2[$h][2] = 'hooks';
3514 $h++;
3515
3516 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=triggers&module='.$module.($forceddirread ? '@'.$dirread : '');
3517 $head2[$h][1] = ($countTriggers <= 0 ? $langs->trans("Triggers") : $langs->trans("Triggers").'<span class="marginleftonlyshort badge">'.$countTriggers."</span>");
3518 $head2[$h][2] = 'triggers';
3519 $h++;
3520
3521 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=widgets&module='.$module.($forceddirread ? '@'.$dirread : '');
3522 $head2[$h][1] = ($countWidgets <= 0 ? $langs->trans("Widgets") : $langs->trans("Widgets").'<span class="marginleftonlyshort badge">'.$countWidgets."</span>");
3523 $head2[$h][2] = 'widgets';
3524 $h++;
3525
3526 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=emailings&module='.$module.($forceddirread ? '@'.$dirread : '');
3527 $head2[$h][1] = ($countEmailingSelectors <= 0 ? $langs->trans("EmailingSelectors") : $langs->trans("EmailingSelectors").'<span class="marginleftonlyshort badge">'.$countEmailingSelectors."</span>");
3528 $head2[$h][2] = 'emailings';
3529 $h++;
3530
3531 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=exportimport&module='.$module.($forceddirread ? '@'.$dirread : '');
3532 $head2[$h][1] = $langs->trans("Export").'-'.$langs->trans("Import");
3533 $head2[$h][2] = 'exportimport';
3534 $h++;
3535
3536 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=css&module='.$module.($forceddirread ? '@'.$dirread : '');
3537 $head2[$h][1] = ($countCss <= 0 ? $langs->trans("CSS") : $langs->trans("CSS")." (".$countCss.")");
3538 $head2[$h][2] = 'css';
3539 $h++;
3540
3541 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=js&module='.$module.($forceddirread ? '@'.$dirread : '');
3542 $head2[$h][1] = ($countJs <= 0 ? $langs->trans("JS") : $langs->trans("JS").'<span class="marginleftonlyshort badge">'.$countJs."</span>");
3543 $head2[$h][2] = 'js';
3544 $h++;
3545
3546 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cli&module='.$module.($forceddirread ? '@'.$dirread : '');
3547 $head2[$h][1] = ($countCLI <= 0 ? $langs->trans("CLI") : $langs->trans("CLI").'<span class="marginleftonlyshort badge">'.$countCLI."</span>");
3548 $head2[$h][2] = 'cli';
3549 $h++;
3550
3551 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cron&module='.$module.($forceddirread ? '@'.$dirread : '');
3552 $head2[$h][1] = $langs->trans("CronList");
3553 $head2[$h][2] = 'cron';
3554 $h++;
3555
3556 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=specifications&module='.$module.($forceddirread ? '@'.$dirread : '');
3557 $head2[$h][1] = ($hasDoc <= 0 ? $langs->trans("Documentation") : $langs->trans("Documentation").'<span class="paddingleft badge">'.$hasDoc."</span>");
3558 $head2[$h][2] = 'specifications';
3559 $h++;
3560
3561 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=buildpackage&module='.$module.($forceddirread ? '@'.$dirread : '');
3562 $head2[$h][1] = $langs->trans("BuildPackage");
3563 $head2[$h][2] = 'buildpackage';
3564 $h++;
3565
3566 $MAXTABFOROBJECT = 15;
3567
3568 print '<!-- Section for a given module -->';
3569
3570 // Note module is inside $dirread
3571
3572 if ($tab == 'description') {
3573 print '<!-- tab=description -->'."\n";
3574 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3575 $pathtofilereadme = $modulelowercase.'/README.md';
3576 $pathtochangelog = $modulelowercase.'/ChangeLog.md';
3577
3578 $realpathofmodule = realpath($dirread.'/'.$modulelowercase);
3579
3580 if ($action != 'editfile' || empty($file)) {
3581 $morehtmlright = '';
3582 if ($realpathofmodule != $dirread.'/'.$modulelowercase) {
3583 $morehtmlright = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', '<span class="opacitymedium">'.$langs->trans("RealPathOfModule").' :</span> <strong class="wordbreak">'.$realpathofmodule.'</strong>').'</div>';
3584 }
3585
3586 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, $morehtmlright, '', $MAXTABFOROBJECT, 'formodulesuffix'); // Description - level 2
3587
3588 print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc".$tab).'</span>';
3589 print '<br><br>';
3590
3591 print '<table>';
3592
3593 print '<tr><td>';
3594 print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3595 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=DESCRIPTION_FLAG">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3596 print '</td></tr>';
3597
3598 // List of setup pages
3599 $listofsetuppages = dol_dir_list($realpathofmodule.'/admin', 'files', 0, '\.php$');
3600 foreach ($listofsetuppages as $setuppage) {
3601 //var_dump($setuppage);
3602 print '<tr><td>';
3603 print '<span class="fa fa-file-o"></span> '.$langs->trans("SetupFile").' : ';
3604 print '<strong class="wordbreak bold"><a href="'.dol_buildpath($modulelowercase.'/admin/'.$setuppage['relativename'], 1).'" target="_test">'.$modulelowercase.'/admin/'.$setuppage['relativename'].'</a></strong>';
3605 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($modulelowercase.'/admin/'.$setuppage['relativename']).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3606 print '</td></tr>';
3607 }
3608
3609 print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ReadmeFile").' : <strong class="wordbreak">'.$pathtofilereadme.'</strong>';
3610 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=markdown&file='.urlencode($pathtofilereadme).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3611 print '</td></tr>';
3612
3613 print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ChangeLog").' : <strong class="wordbreak">'.$pathtochangelog.'</strong>';
3614 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=markdown&file='.urlencode($pathtochangelog).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3615 print '</td></tr>';
3616
3617 print '</table>';
3618 print '<br>';
3619
3620 print load_fiche_titre($form->textwithpicto($langs->trans("DescriptorFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofile), '', '');
3621
3622 if (is_object($moduleobj)) {
3623 print '<div class="underbanner clearboth"></div>';
3624 print '<div class="fichecenter">';
3625 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3626 print '<input type="hidden" name="token" value="'.newToken().'">';
3627 print '<input type="hidden" name="action" value="update_props_module">';
3628 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3629 print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
3630 print '<input type="hidden" name="keydescription" value="'.dol_escape_htmltag(GETPOST('keydescription', 'alpha')).'">';
3631 print '<table class="border centpercent">';
3632 print '<tr class="liste_titre"><td class="titlefield">';
3633 print $langs->trans("Parameter");
3634 print '</td><td>';
3635 print $langs->trans("Value");
3636 print '</td></tr>';
3637
3638 print '<tr><td>';
3639 print $langs->trans("IdModule");
3640 print '</td><td>';
3641 print $moduleobj->numero;
3642 print '<span class="opacitymedium">';
3643 print ' &nbsp; (';
3644 print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
3645 print ' - <a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>)';
3646 print '</span>';
3647 print '</td></tr>';
3648
3649 print '<tr><td>';
3650 print $langs->trans("ModuleName");
3651 print '</td><td>';
3652 print $moduleobj->getName();
3653 print '</td></tr>';
3654
3655 print '<tr><td>';
3656 print $langs->trans("Description");
3657 print '</td><td>';
3658 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'desc') {
3659 print '<input class="minwidth500" name="propsmodule" value="'.dol_escape_htmltag($moduleobj->description).'">';
3660 print '<input class="reposition button smallpaddingimp" type="submit" name="modifydesc" value="'.$langs->trans("Modify").'"/>';
3661 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3662 } else {
3663 print $moduleobj->description;
3664 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_moduledescription&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=desc">'.img_edit().'</a>';
3665
3666 $moduledescritpionautotrans = $moduleobj->getDesc();
3667 if ($moduledescritpionautotrans != "Module".$moduleobj->name."Desc") {
3668 // $moduledescritpionautotrans has been found into a translation file
3669 print ' '.$form->textwithpicto('', $langs->trans("ModuleTranslatedIntoLangForKeyInto", "Module".$moduleobj->name."Desc", $moduledescritpionautotrans));
3670 } elseif ($moduledescritpionautotrans != "Module".$moduleobj->numero."Desc") {
3671 // $moduledescritpionautotrans has been found into a translation file
3672 print ' '.$form->textwithpicto('', $langs->trans("ModuleTranslatedIntoLangForKeyInto", "Module".$moduleobj->numero."Desc", $moduledescritpionautotrans));
3673 }
3674 }
3675 print '</td></tr>';
3676
3677 print '<tr><td>';
3678 print $langs->trans("Version");
3679 print '</td><td>';
3680 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'version') {
3681 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->getVersion()).'">';
3682 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyversion" value="'.$langs->trans("Modify").'"/>';
3683 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3684 } else {
3685 print $moduleobj->getVersion();
3686 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_moduledescription&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=version">'.img_edit().'</a>';
3687 }
3688 print '</td></tr>';
3689
3690 print '<tr><td>';
3691 print $langs->trans("Family");
3692 //print "<br>'crm','financial','hr','projects','products','ecm','technic','interface','other'";
3693 print '</td><td>';
3694 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'family') {
3695 print '<select name="propsmodule" id="family" class="minwidth400">';
3696 $arrayoffamilies = array(
3697 'hr' => "ModuleFamilyHr",
3698 'crm' => "ModuleFamilyCrm",
3699 'srm' => "ModuleFamilySrm",
3700 'financial' => 'ModuleFamilyFinancial',
3701 'products' => 'ModuleFamilyProducts',
3702 'projects' => 'ModuleFamilyProjects',
3703 'ecm' => 'ModuleFamilyECM',
3704 'technic' => 'ModuleFamilyTechnic',
3705 'portal' => 'ModuleFamilyPortal',
3706 'interface' => 'ModuleFamilyInterface',
3707 'base' => 'ModuleFamilyBase',
3708 'other' => 'ModuleFamilyOther'
3709 );
3710 print '<option value="'.$moduleobj->family.'" data-html="'.dol_escape_htmltag($langs->trans($arrayoffamilies[$moduleobj->family]).' <span class="opacitymedium">- '.$moduleobj->family.'</span>').'">'.$langs->trans($arrayoffamilies[$moduleobj->family]).'</option>';
3711 foreach ($arrayoffamilies as $key => $value) {
3712 if ($key != $moduleobj->family) {
3713 print '<option value="'.$key.'" data-html="'.dol_escape_htmltag($langs->trans($value).' <span class="opacitymedium">- '.$key.'</span>').'">'.$langs->trans($value).'</option>';
3714 }
3715 }
3716 print '</select>';
3717 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyfamily" value="'.$langs->trans("Modify").'"/>';
3718 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3719 } else {
3720 print $moduleobj->family;
3721 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_moduledescription&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=family">'.img_edit().'</a>';
3722 }
3723 print '</td></tr>';
3724
3725 print '<tr><td>';
3726 print $langs->trans("Picto");
3727 print '</td><td>';
3728 if ($action == 'edit_modulepicto' && GETPOST('keydescription', 'alpha') === 'picto') {
3729 print '<input class="minwidth500" name="propsmodule" value="'.dol_escape_htmltag($moduleobj->picto).'">';
3730 print '<input class="reposition button smallpaddingimp" type="submit" name="modifypicto" value="'.$langs->trans("Modify").'"/>';
3731 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3732 } else {
3733 print $moduleobj->picto;
3734 print ' &nbsp; '.img_picto('', $moduleobj->picto, 'class="valignmiddle pictomodule paddingrightonly"');
3735 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_modulepicto&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=picto">'.img_edit().'</a>';
3736 }
3737 print '</td></tr>';
3738
3739 print '<tr><td>';
3740 print $langs->trans("EditorName");
3741 print '</td><td>';
3742 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'editor_name') {
3743 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->editor_name).'">';
3744 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyname" value="'.$langs->trans("Modify").'"/>';
3745 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3746 } else {
3747 print $moduleobj->editor_name;
3748 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_moduledescription&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=editor_name">'.img_edit().'</a>';
3749 }
3750 print '</td></tr>';
3751
3752 print '<tr><td>';
3753 print $langs->trans("EditorUrl");
3754 print '</td><td>';
3755 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'editor_url') {
3756 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->editor_url).'">';
3757 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyeditorurl" value="'.$langs->trans("Modify").'"/>';
3758 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3759 } else {
3760 if (!empty($moduleobj->editor_url)) {
3761 print '<a href="'.$moduleobj->editor_url.'" target="_blank" rel="noopener">'.$moduleobj->editor_url.' '.img_picto('', 'globe').'</a>';
3762 }
3763 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_moduledescription&token='.newToken().'&tab='.urlencode($tab).'&module='.urlencode($module).'&keydescription=editor_url">'.img_edit().'</a>';
3764 }
3765 print '</td></tr>';
3766
3767 print '</table>';
3768 print '</form>';
3769 } else {
3770 print $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
3771 }
3772
3773 if (!empty($moduleobj)) {
3774 print '<br><br>';
3775
3776 // Readme file
3777 print load_fiche_titre($form->textwithpicto($langs->trans("ReadmeFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofilereadme), '', '');
3778
3779 print '<!-- readme file -->';
3780 if (dol_is_file($dirread.'/'.$pathtofilereadme)) {
3781 print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getDescLong().'</div>';
3782 } else {
3783 print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtofilereadme).'</span>';
3784 }
3785
3786 print '<br><br>';
3787
3788 // ChangeLog
3789 print load_fiche_titre($form->textwithpicto($langs->trans("ChangeLog"), $langs->transnoentitiesnoconv("File").' '.$pathtochangelog), '', '');
3790
3791 print '<!-- changelog file -->';
3792 if (dol_is_file($dirread.'/'.$pathtochangelog)) {
3793 print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getChangeLog().'</div>';
3794 } else {
3795 print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtochangelog).'</span>';
3796 }
3797 }
3798
3799 print dol_get_fiche_end();
3800 } else { // Edit text file
3801 $fullpathoffile = dol_buildpath($file, 0, 1); // Description - level 2
3802
3803 if ($fullpathoffile) {
3804 $content = file_get_contents($fullpathoffile);
3805 }
3806
3807 // New module
3808 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3809 print '<input type="hidden" name="token" value="'.newToken().'">';
3810 print '<input type="hidden" name="action" value="savefile">';
3811 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3812 print '<input type="hidden" name="tab" value="'.$tab.'">';
3813 print '<input type="hidden" name="module" value="'.$module.'">';
3814
3815 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', 0, 'formodulesuffix');
3816
3817 $posCursor = (empty($find)) ? array() : array('find' => $find);
3818 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
3819 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
3820
3821 print dol_get_fiche_end();
3822
3823 print '<center>';
3824 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3825 print ' &nbsp; ';
3826 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3827 print '</center>';
3828
3829 print '</form>';
3830 }
3831 } else {
3832 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', $MAXTABFOROBJECT, 'formodulesuffix'); // Level 2
3833 }
3834
3835 if ($tab == 'languages') {
3836 print '<!-- tab=languages -->'."\n";
3837 if ($action != 'editfile' || empty($file)) {
3838 print '<span class="opacitymedium">'.$langs->trans("LanguageDefDesc").'</span><br>';
3839 print '<br>';
3840
3841
3842 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3843 print '<input type="hidden" name="token" value="'.newToken().'">';
3844 print '<input type="hidden" name="action" value="addlanguage">';
3845 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3846 print '<input type="hidden" name="tab" value="'.$tab.'">';
3847 print '<input type="hidden" name="module" value="'.$module.'">';
3848 print $formadmin->select_language(getDolGlobalString('MAIN_LANG_DEFAULT'), 'newlangcode', 0, array(), 1, 0, 0, 'minwidth300', 1);
3849 print '<input type="submit" name="addlanguage" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("AddLanguageFile")).'"><br>';
3850 print '</form>';
3851
3852 print '<br>';
3853 print '<br>';
3854
3855 $modulelowercase = strtolower($module);
3856
3857 // Dir for module
3858 $diroflang = dol_buildpath($modulelowercase, 0);
3859 $diroflang .= '/langs';
3860 $langfiles = dol_dir_list($diroflang, 'files', 1, '\.lang$');
3861
3862 if (!preg_match('/custom/', $dirread)) {
3863 // If this is not a module into custom
3864 $diroflang = $dirread;
3865 $diroflang .= '/langs';
3866 $langfiles = dol_dir_list($diroflang, 'files', 1, $modulelowercase.'\.lang$');
3867 }
3868
3869 print '<table class="none">';
3870 foreach ($langfiles as $langfile) {
3871 $pathtofile = $modulelowercase.'/langs/'.$langfile['relativename'];
3872 if (!preg_match('/custom/', $dirread)) { // If this is not a module into custom
3873 $pathtofile = 'langs/'.$langfile['relativename'];
3874 }
3875 print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("LanguageFile").' '.basename(dirname($pathtofile)).' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3876 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=ini&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3877 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
3878 print '</td>';
3879 }
3880 print '</table>';
3881 } else {
3882 // Edit text language file
3883
3884 //print $langs->trans("UseAsciiDocFormat").'<br>';
3885
3886 $fullpathoffile = dol_buildpath($file, 0);
3887
3888 $content = file_get_contents($fullpathoffile);
3889
3890 // New module
3891 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3892 print '<input type="hidden" name="token" value="'.newToken().'">';
3893 print '<input type="hidden" name="action" value="savefile">';
3894 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3895 print '<input type="hidden" name="tab" value="'.$tab.'">';
3896 print '<input type="hidden" name="module" value="'.$module.'">';
3897
3898 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
3899 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'text'));
3900 print '<br>';
3901 print '<center>';
3902 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3903 print ' &nbsp; ';
3904 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3905 print '</center>';
3906
3907 print '</form>';
3908 }
3909 }
3910
3911 if ($tab == 'objects') {
3912 print '<!-- tab=objects -->'."\n";
3913 $head3 = array();
3914 $h = 0;
3915
3916 // Dir for module
3917 $dir = $dirread.'/'.$modulelowercase.'/class';
3918
3919 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=newobject';
3920 $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewObjectInModulebuilder").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
3921 $head3[$h][2] = 'newobject';
3922 $h++;
3923
3924 // Scan for object class files
3925 $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
3926
3927 $firstobjectname = '';
3928 foreach ($listofobject as $fileobj) {
3929 if (preg_match('/^api_/', $fileobj['name'])) {
3930 continue;
3931 }
3932 if (preg_match('/^actions_/', $fileobj['name'])) {
3933 continue;
3934 }
3935
3936 $tmpcontent = file_get_contents($fileobj['fullname']);
3937 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
3938 //$objectname = preg_replace('/\.txt$/', '', $fileobj['name']);
3939 $objectname = $reg[1];
3940 if (empty($firstobjectname)) {
3941 $firstobjectname = $objectname;
3942 }
3943 $pictoname = 'generic';
3944 if (preg_match('/\$picto\s*=\s*["\']([^"\']+)["\']/', $tmpcontent, $reg)) {
3945 $pictoname = $reg[1];
3946 }
3947
3948 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname;
3949 $head3[$h][1] = img_picto('', $pictoname, 'class="pictofixedwidth valignmiddle"').$objectname;
3950 $head3[$h][2] = $objectname;
3951 $h++;
3952 }
3953 }
3954
3955 if ($h > 1) {
3956 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=deleteobject';
3957 $head3[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
3958 $head3[$h][2] = 'deleteobject';
3959 $h++;
3960 }
3961
3962 // If tabobj was not defined, then we check if there is one obj. If yes, we force on it, if no, we will show tab to create new objects.
3963 if ($tabobj == 'newobjectifnoobj') {
3964 if ($firstobjectname) {
3965 $tabobj = $firstobjectname;
3966 } else {
3967 $tabobj = 'newobject';
3968 }
3969 }
3970
3971 print dol_get_fiche_head($head3, $tabobj, '', -1, '', 0, '', '', 0, 'forobjectsuffix'); // Level 3
3972
3973
3974 if ($tabobj == 'newobject') {
3975 // New object tab
3976 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3977 print '<input type="hidden" name="token" value="'.newToken().'">';
3978 print '<input type="hidden" name="action" value="initobject">';
3979 print '<input type="hidden" name="tab" value="objects">';
3980 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3981
3982 print '<span class="opacitymedium">'.$langs->trans("EnterNameOfObjectDesc").'</span><br><br>';
3983
3984 print '<div class="tagtable">';
3985
3986 print '<div class="tagtr"><div class="tagtd">';
3987 print '<span class="opacitymedium">'.$langs->trans("ObjectKey").'</span> &nbsp; ';
3988 print '</div><div class="tagtd">';
3989 print '<input type="text" name="objectname" maxlength="64" value="'.dol_escape_htmltag(GETPOSTISSET('objectname') ? GETPOST('objectname', 'alpha') : $modulename).'" autofocus>';
3990 print $form->textwithpicto('', $langs->trans("Example").': MyObject, ACamelCaseName, ...');
3991 print '</div></div>';
3992
3993 print '<div class="tagtr"><div class="tagtd">';
3994 print '<span class="opacitymedium">'.$langs->trans("Picto").'</span> &nbsp; ';
3995 print '</div><div class="tagtd">';
3996 print '<input type="text" name="idpicto" value="fa-file-o" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
3997 print $form->textwithpicto('', $langs->trans("Example").': fa-file-o, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
3998 print '</div></div>';
3999
4000 print '<div class="tagtr"><div class="tagtd">';
4001 print '<span class="opacitymedium">'.$langs->trans("DefinePropertiesFromExistingTable").'</span> &nbsp; ';
4002 print '</div><div class="tagtd">';
4003 print '<input type="text" name="initfromtablename" value="'.GETPOST('initfromtablename').'" placeholder="'.$langs->trans("TableName").'">';
4004 print $form->textwithpicto('', $langs->trans("DefinePropertiesFromExistingTableDesc").'<br>'.$langs->trans("DefinePropertiesFromExistingTableDesc2"));
4005 print '</div></div>';
4006
4007 print '</div>';
4008
4009 print '<br>';
4010 print '<input type="checkbox" name="includerefgeneration" id="includerefgeneration" value="includerefgeneration"> <label class="margintoponly" for="includerefgeneration">'.$form->textwithpicto($langs->trans("IncludeRefGeneration"), $langs->trans("IncludeRefGenerationHelp")).'</label><br>';
4011 print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
4012 print '<input type="checkbox" name="generatepermissions" id="generatepermissions" value="generatepermissions"> <label for="generatepermissions">'.$form->textwithpicto($langs->trans("GeneratePermissions"), $langs->trans("GeneratePermissionsHelp")).'</label><br>';
4013 print '<br>';
4014 print '<input type="submit" class="button small" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4015 print '<br>';
4016 print '<br>';
4017 /*
4018 print '<br>';
4019 print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
4020 print '<br>';
4021 print '<br>';
4022 //print '<input type="checkbox" name="initfromtablecheck"> ';
4023 print $langs->trans("InitStructureFromExistingTable");
4024 print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
4025 print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4026 print '<br>';
4027 */
4028
4029 print '</form>';
4030 } elseif ($tabobj == 'createproperty') {
4031 $attributesUnique = array(
4032 'proplabel' => $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey")),
4033 'propname' => $form->textwithpicto($langs->trans("Code"), $langs->trans("PropertyDesc"), 1, 'help', 'extracss', 0, 3, 'propertyhelp'),
4034 'proptype' => $form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp'),
4035 'proparrayofkeyval' => $form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")),
4036 'propnotnull' => $form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")),
4037 'propdefault' => $langs->trans("DefaultValue"),
4038 'propindex' => $langs->trans("DatabaseIndex"),
4039 'propforeignkey' => $form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp'),
4040 'propposition' => $langs->trans("Position"),
4041 'propenabled' => $form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp'),
4042 'propvisible' => $form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp'),
4043 'propnoteditable' => $langs->trans("NotEditable"),
4044 //'propalwayseditable' => $langs->trans("AlwaysEditable"),
4045 'propsearchall' => $form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")),
4046 'propisameasure' => $form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")),
4047 'propcss' => $langs->trans("CSSClass"),
4048 'propcssview' => $langs->trans("CSSViewClass"),
4049 'propcsslist' => $langs->trans("CSSListClass"),
4050 'prophelp' => $langs->trans("KeyForTooltip"),
4051 'propshowoncombobox' => $langs->trans("ShowOnCombobox"),
4052 //'propvalidate' => $form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")),
4053 'propcomment' => $langs->trans("Comment"),
4054 );
4055 print '<form action="'.$_SERVER["PHP_SELF"].'?tab=objects&module='.urlencode($module).'&tabobj=createproperty&obj='.urlencode(GETPOST('obj')).'" method="POST">';
4056 print '<input type="hidden" name="token" value="'.newToken().'">';
4057 print '<input type="hidden" name="action" value="addproperty">';
4058 print '<input type="hidden" name="tab" value="objects">';
4059 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4060 print '<input type="hidden" name="obj" value="'.dol_escape_htmltag(GETPOST('obj')).'">';
4061
4062 print '<table class="border centpercent tableforfieldcreate">'."\n";
4063 $counter = 0;
4064 foreach ($attributesUnique as $key => $attribute) {
4065 if ($counter % 2 === 0) {
4066 print '<tr>';
4067 }
4068 if ($key == 'propname' || $key == 'proplabel') {
4069 print '<td class="titlefieldcreate fieldrequired">'.$attribute.'</td><td class="valuefieldcreate maxwidth50"><input class="maxwidth200" id="'.$key.'" type="text" name="'.$key.'" value="'.dol_escape_htmltag(GETPOST($key, 'alpha')).'"></td>';
4070 } elseif ($key == 'proptype') {
4071 print '<td class="titlefieldcreate fieldrequired">'.$attribute.'</td><td class="valuefieldcreate maxwidth50">';
4072 print '<input class="maxwidth200" id="'.$key.'" list="datalist'.$key.'" type="text" name="'.$key.'" value="'.dol_escape_htmltag(GETPOST($key, 'alpha')).'">';
4073 //print '<div id="suggestions"></div>';
4074 print '<datalist id="datalist'.$key.'">';
4075 print '<option>varchar(128)</option>';
4076 print '<option>email</option>';
4077 print '<option>phone</option>';
4078 print '<option>ip</option>';
4079 print '<option>url</option>';
4080 print '<option>password</option>';
4081 print '<option>text</option>';
4082 print '<option>html</option>';
4083 print '<option>date</option>';
4084 print '<option>datetime</option>';
4085 print '<option>integer</option>';
4086 print '<option>double(28,4)</option>';
4087 print '<option>real</option>';
4088 print '<option>integer:ClassName:RelativePath/To/ClassFile.class.php[:1[:FILTER]]</option>';
4089 // Combo with list of fields
4090 /*
4091 if (empty($formadmin)) {
4092 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
4093 $formadmin = new FormAdmin($db);
4094 }
4095 print $formadmin->selectTypeOfFields($key, GETPOST($key, 'alpha'));
4096 */
4097 print '</datalist>';
4098 print '</td>';
4099 //} elseif ($key == 'propvalidate') {
4100 // print '<td class="titlefieldcreate">'.$attribute.'</td><td class="valuefieldcreate maxwidth50"><input type="number" step="1" min="0" max="1" class="text maxwidth100" value="'.dol_escape_htmltag(GETPOST($key, 'alpha')).'"></td>';
4101 } elseif ($key == 'propvisible') {
4102 print '<td class="titlefieldcreate">'.$attribute.'</td><td class="valuefieldcreate"><input class="maxwidth200" type="text" name="'.$key.'" value="'.dol_escape_htmltag(GETPOSTISSET($key) ? GETPOST($key, 'alpha') : "1").'"></td>';
4103 } elseif ($key == 'propenabled') {
4104 //$default = "isModEnabled('".strtolower($module)."')";
4105 $default = 1;
4106 print '<td class="titlefieldcreate">'.$attribute.'</td><td class="valuefieldcreate"><input class="maxwidth200" type="text" name="'.$key.'" value="'.dol_escape_htmltag(GETPOSTISSET($key) ? GETPOST($key, 'alpha') : $default).'"></td>';
4107 } elseif ($key == 'proparrayofkeyval') {
4108 print '<td class="titlefieldcreate tdproparrayofkeyval">'.$attribute.'</td><td class="valuefieldcreate"><textarea class="maxwidth200" name="'.$key.'">'.dol_escape_htmltag(GETPOSTISSET($key) ? GETPOST($key, 'alpha') : "").'</textarea></td>';
4109 } else {
4110 print '<td class="titlefieldcreate">'.$attribute.'</td><td class="valuefieldcreate"><input class="maxwidth200" type="text" name="'.$key.'" value="'.dol_escape_htmltag(GETPOSTISSET($key) ? GETPOST($key, 'alpha') : '').'"></td>';
4111 }
4112 $counter++;
4113 if ($counter % 2 === 0) {
4114 print '</tr>';
4115 }
4116 }
4117 if ($counter % 2 !== 0) {
4118 while ($counter % 2 !== 0) {
4119 print '<td></td>';
4120 $counter++;
4121 }
4122 print '</tr>';
4123 }
4124 print '</table><br>'."\n";
4125 print '<div class="center">';
4126 print '<input type="submit" class="button button-save" name="add" value="' . dol_escape_htmltag($langs->trans('Create')) . '">';
4127 print '<input type="button" class="button button-cancel" name="cancel" value="' . dol_escape_htmltag($langs->trans('Cancel')) . '" onclick="goBack()">';
4128 print '</div>';
4129 print '</form>';
4130 // javascript
4131 print '<script>
4132 function goBack() {
4133 var url = "'.$_SERVER["PHP_SELF"].'?tab=objects&module='.urlencode($module).'";
4134 window.location.href = url;
4135 }
4136 $(document).ready(function() {
4137 $("#proplabel").on("keyup", function() {
4138 console.log("key up on label");
4139 s = cleanString($("#proplabel").val());
4140 $("#propname").val(s);
4141 });
4142
4143 function cleanString( stringtoclean )
4144 {
4145 // allow "a-z", "A-Z", "0-9" and "_"
4146 stringtoclean = stringtoclean.replace(/[^a-z0-9_]+/ig, "");
4147 stringtoclean = stringtoclean.toLowerCase();
4148 if (!isNaN(stringtoclean)) {
4149 return ""
4150 }
4151 while ( stringtoclean.length > 1 && !isNaN( stringtoclean.charAt(0)) ){
4152 stringtoclean = stringtoclean.substr(1)
4153 }
4154 if (stringtoclean.length > 28) {
4155 stringtoclean = stringtoclean.substring(0, 27);
4156 }
4157 return stringtoclean;
4158 }
4159
4160 });';
4161 print '</script>';
4162 } elseif ($tabobj == 'deleteobject') {
4163 // Delete object tab
4164 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4165 print '<input type="hidden" name="token" value="'.newToken().'">';
4166 print '<input type="hidden" name="action" value="confirm_deleteobject">';
4167 print '<input type="hidden" name="tab" value="objects">';
4168 print '<input type="hidden" name="tabobj" value="deleteobject">';
4169 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4170
4171 print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
4172
4173 print '<input type="text" name="objectname" value="" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'" autofocus>';
4174 print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4175 print '</form>';
4176 } else {
4177 // tabobj = module
4178 if ($action == 'deleteproperty') {
4179 $formconfirm = $form->formconfirm(
4180 $_SERVER["PHP_SELF"].'?propertykey='.urlencode(GETPOST('propertykey', 'alpha')).'&objectname='.urlencode($objectname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj),
4181 $langs->trans('Delete'),
4182 $langs->trans('ConfirmDeleteProperty', GETPOST('propertykey', 'alpha')),
4183 'confirm_deleteproperty',
4184 '',
4185 0,
4186 1
4187 );
4188
4189 // Print form confirm
4190 print $formconfirm;
4191 }
4192 if ($action != 'editfile' || empty($file)) {
4193 try {
4194 //$pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4195
4196 $pathtoclass = strtolower($module).'/class/'.strtolower($tabobj).'.class.php';
4197 $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'.class.php';
4198 $pathtoagenda = strtolower($module).'/'.strtolower($tabobj).'_agenda.php';
4199 $pathtocard = strtolower($module).'/'.strtolower($tabobj).'_card.php';
4200 $pathtodocument = strtolower($module).'/'.strtolower($tabobj).'_document.php';
4201 $pathtolist = strtolower($module).'/'.strtolower($tabobj).'_list.php';
4202 $pathtonote = strtolower($module).'/'.strtolower($tabobj).'_note.php';
4203 $pathtocontact = strtolower($module).'/'.strtolower($tabobj).'_contact.php';
4204 $pathtophpunit = strtolower($module).'/test/phpunit/'.strtolower($tabobj).'Test.php';
4205
4206 // Try to load object class file
4207 clearstatcache(true);
4208 if (function_exists('opcache_invalidate')) {
4209 opcache_invalidate($dirread.'/'.$pathtoclass, true); // remove the include cache hell !
4210 }
4211
4212 if (empty($forceddirread) && empty($dirread)) {
4213 $result = dol_include_once($pathtoclass);
4214 $stringofinclude = "dol_include_once(".$pathtoclass.")";
4215 } else {
4216 $result = include_once $dirread.'/'.$pathtoclass;
4217 $stringofinclude = "@include_once ".$dirread.'/'.$pathtoclass;
4218 }
4219
4220 if (class_exists($tabobj)) {
4221 try {
4222 $tmpobject = @new $tabobj($db);
4223 } catch (Exception $e) {
4224 dol_syslog('Failed to load Constructor of class: '.$e->getMessage(), LOG_WARNING);
4225 }
4226 } else {
4227 print '<span class="warning">'.$langs->trans('Failed to find the class '.$tabobj.' despite the '.$stringofinclude).'</span><br><br>';
4228 }
4229
4230 // Define path for sql file
4231 $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
4232 $result = dol_buildpath($pathtosql);
4233 if (! dol_is_file($result)) {
4234 $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'.sql';
4235 $result = dol_buildpath($pathtosql);
4236 if (! dol_is_file($result)) {
4237 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
4238 $result = dol_buildpath($pathtosql);
4239 if (! dol_is_file($result)) {
4240 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
4241 $result = dol_buildpath($pathtosql);
4242 if (! dol_is_file($result)) {
4243 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'.sql';
4244 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields.sql';
4245 $result = dol_buildpath($pathtosql);
4246 } else {
4247 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields-'.strtolower($module).'.sql';
4248 }
4249 } else {
4250 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
4251 }
4252 } else {
4253 $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields.sql';
4254 }
4255 } else {
4256 $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
4257 }
4258 $pathtosqlroot = preg_replace('/\/llx_.*$/', '', $pathtosql);
4259
4260 $pathtosqlkey = preg_replace('/\.sql$/', '.key.sql', $pathtosql);
4261 $pathtosqlextrakey = preg_replace('/\.sql$/', '.key.sql', $pathtosqlextra);
4262
4263 $pathtolib = strtolower($module).'/lib/'.strtolower($module).'.lib.php';
4264 $pathtoobjlib = strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($tabobj).'.lib.php';
4265
4266 $tmpobject = $tmpobject ?? null; // @phan-suppress-current-line PhanPluginDuplicateExpressionAssignmentOperation
4267 if (is_object($tmpobject) && property_exists($tmpobject, 'picto')) {
4268 $pathtopicto = $tmpobject->picto;
4269 $realpathtopicto = '';
4270 } else {
4271 $pathtopicto = strtolower($module).'/img/object_'.strtolower($tabobj).'.png';
4272 $realpathtopicto = $dirread.'/'.$pathtopicto;
4273 }
4274
4275 //var_dump($pathtoclass);
4276 //var_dump($dirread);
4277 $realpathtoclass = $dirread.'/'.$pathtoclass;
4278 $realpathtoapi = $dirread.'/'.$pathtoapi;
4279 $realpathtoagenda = $dirread.'/'.$pathtoagenda;
4280 $realpathtocard = $dirread.'/'.$pathtocard;
4281 $realpathtodocument = $dirread.'/'.$pathtodocument;
4282 $realpathtolist = $dirread.'/'.$pathtolist;
4283 $realpathtonote = $dirread.'/'.$pathtonote;
4284 $realpathtocontact = $dirread.'/'.$pathtocontact;
4285 $realpathtophpunit = $dirread.'/'.$pathtophpunit;
4286 $realpathtosql = $dirread.'/'.$pathtosql;
4287 $realpathtosqlextra = $dirread.'/'.$pathtosqlextra;
4288 $realpathtosqlkey = $dirread.'/'.$pathtosqlkey;
4289 $realpathtosqlextrakey = $dirread.'/'.$pathtosqlextrakey;
4290 $realpathtolib = $dirread.'/'.$pathtolib;
4291 $realpathtoobjlib = $dirread.'/'.$pathtoobjlib;
4292
4293 if (empty($realpathtoapi)) { // For compatibility with some old modules
4294 $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'s.class.php';
4295 $realpathtoapi = $dirread.'/'.$pathtoapi;
4296 }
4297
4298 $urloflist = dol_buildpath('/'.$pathtolist, 1);
4299 $urlofcard = dol_buildpath('/'.$pathtocard, 1);
4300
4301 $objs = array();
4302
4303 print '<!-- section for object -->';
4304 print '<div class="fichehalfleft smallxxx">';
4305 // Main DAO class file
4306 print '<span class="fa fa-file-o"></span> '.$langs->trans("ClassFile").' : <strong>'.(dol_is_file($realpathtoclass) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtoclass).(dol_is_file($realpathtoclass) ? '' : '</strike>').'</strong>';
4307 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtoclass).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4308 print '<br>';
4309 // Image
4310 if ($realpathtopicto && dol_is_file($realpathtopicto)) {
4311 print '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : <strong>'.(dol_is_file($realpathtopicto) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtopicto).(dol_is_file($realpathtopicto) ? '' : '</strike>').'</strong>';
4312 //print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread?'@'.$dirread:'').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtopicto).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4313 print '<br>';
4314 } elseif (!empty($tmpobject)) {
4315 print '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : '.img_picto('', $tmpobject->picto, 'class="pictofixedwidth valignmiddle"').$tmpobject->picto;
4316 print '<br>';
4317 }
4318
4319 // API file
4320 print '<br>';
4321 print '<span class="fa fa-file-o"></span> '.$langs->trans("ApiClassFile").' : <strong class="wordbreak">'.(dol_is_file($realpathtoapi) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtoapi).(dol_is_file($realpathtoapi) ? '' : '</span></strike>').'</strong>';
4322 if (dol_is_file($realpathtoapi)) {
4323 $file = file_get_contents($realpathtoapi);
4324 if (preg_match('/var '.$tabobj.'\s+([^\s]*)\s/ims', $file, $objs)) {
4325 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtoapi).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4326 print ' ';
4327 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtoapi).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4328 print $form->textwithpicto('', $langs->trans("InfoForApiFile"), 1, 'warning');
4329 print ' &nbsp; ';
4330 // Comparing to null (phan considers $modulelowercase can be null here)
4331 if ($modulelowercase !== null && !isModEnabled($modulelowercase)) { // If module is not activated
4332 print '<a href="#" class="classfortooltip" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled", $module).'"><strike>'.$langs->trans("ApiExplorer").'</strike></a>';
4333 } else {
4334 print '<a href="'.DOL_URL_ROOT.'/api/index.php/explorer/" target="apiexplorer">'.$langs->trans("ApiExplorer").'</a>';
4335 }
4336 } else {
4337 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initapi&token='.newToken().'&format=php&file='.urlencode($pathtoapi).'">'.img_picto($langs->trans('AddAPIsForThisObject'), 'generate', 'class="paddingleft"').'</a>';
4338 }
4339 } else {
4340 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initapi&token='.newToken().'&format=php&file='.urlencode($pathtoapi).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4341 }
4342 // PHPUnit
4343 print '<br>';
4344 print '<span class="fa fa-file-o"></span> '.$langs->trans("TestClassFile").' : <strong class="wordbreak">'.(dol_is_file($realpathtophpunit) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtophpunit).(dol_is_file($realpathtophpunit) ? '' : '</span></strike>').'</strong>';
4345 if (dol_is_file($realpathtophpunit)) {
4346 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtophpunit).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4347 print ' ';
4348 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtophpunit).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4349 } else {
4350 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initphpunit&token='.newToken().'&format=php&file='.urlencode($pathtophpunit).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4351 }
4352 print '<br>';
4353
4354 print '<br>';
4355
4356 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForLib").' : <strong class="wordbreak">'.(dol_is_file($realpathtolib) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtolib).(dol_is_file($realpathtolib) ? '' : '</strike>').'</strong>';
4357 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtolib).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4358 print '<br>';
4359 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForObjLib").' : <strong class="wordbreak">'.(dol_is_file($realpathtoobjlib) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtoobjlib).(dol_is_file($realpathtoobjlib) ? '' : '</strike>').'</strong>';
4360 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtoobjlib).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4361 print '<br>';
4362
4363 print '<br>';
4364 print '<span class="fa fa-file-o"></span> '.$langs->trans("SqlFile").' : <strong class="wordbreak">'.(dol_is_file($realpathtosql) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtosql).(dol_is_file($realpathtosql) ? '' : '</strike>').'</strong>';
4365 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=sql&file='.urlencode($pathtosql).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4366 print ' &nbsp; <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=droptable&token='.newToken().'">'.$langs->trans("DropTableIfEmpty").'</a>';
4367 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4368 print '<br>';
4369 print '<span class="fa fa-file-o"></span> '.$langs->trans("SqlFileKey").' : <strong class="wordbreak">'.(dol_is_file($realpathtosqlkey) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtosqlkey).(dol_is_file($realpathtosqlkey) ? '' : '</strike>').'</strong>';
4370 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=sql&file='.urlencode($pathtosqlkey).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4371 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4372 print '<br>';
4373 print '<span class="fa fa-file-o"></span> '.$langs->trans("SqlFileExtraFields").' : <strong class="wordbreak">'.(dol_is_file($realpathtosqlextra) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtosqlextra).(dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey) ? '' : '</span></strike>').'</strong>';
4374 if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
4375 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&file='.urlencode($pathtosqlextra).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4376 print ' ';
4377 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtosqlextra).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4378 print ' &nbsp; ';
4379 print '<a class="reposition editfielda" href="'.$_SERVER["PHP_SELF"].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=droptableextrafields&token='.newToken().'">'.$langs->trans("DropTableIfEmpty").'</a>';
4380 } else {
4381 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initsqlextrafields&token='.newToken().'&format=sql&file='.urlencode($pathtosqlextra).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4382 }
4383 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4384 print '<br>';
4385 print '<span class="fa fa-file-o"></span> '.$langs->trans("SqlFileKeyExtraFields").' : <strong class="wordbreak">'.(dol_is_file($realpathtosqlextrakey) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtosqlextrakey).(dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey) ? '' : '</span></strike>').'</strong>';
4386 if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
4387 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=sql&file='.urlencode($pathtosqlextrakey).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4388 print ' ';
4389 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtosqlextrakey).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4390 } else {
4391 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initsqlextrafields&token='.newToken().'&format=sql&file='.urlencode($pathtosqlextra).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4392 }
4393 print '<br>';
4394 print '</div>';
4395
4396 print '<div class="fichehalfleft smallxxxx">';
4397 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForList").' : <strong class="wordbreak"><a href="'.$urloflist.'" target="_test">'.(dol_is_file($realpathtolist) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtolist).(dol_is_file($realpathtolist) ? '' : '</span></strike>').'</a></strong>';
4398 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtolist).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4399 print '<br>';
4400 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForCreateEditView").' : <strong class="wordbreak"><a href="'.$urlofcard.'?action=create" target="_test">'.(dol_is_file($realpathtocard) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtocard).(dol_is_file($realpathtocard) ? '' : '</strike>').'?action=create</a></strong>';
4401 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtocard).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4402 print '<br>';
4403 // Page contact
4404 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForContactTab").' : <strong class="wordbreak">'.(dol_is_file($realpathtocontact) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtocontact).(dol_is_file($realpathtocontact) ? '' : '</span></strike>').'</strong>';
4405 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtocontact).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4406 if (dol_is_file($realpathtocontact)) {
4407 print ' ';
4408 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtocontact).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4409 } else {
4410 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initpagecontact&token='.newToken().'&format=php&file='.urlencode($pathtocontact).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4411 }
4412 print '<br>';
4413 // Page document
4414 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForDocumentTab").' : <strong class="wordbreak">'.(dol_is_file($realpathtodocument) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtodocument).(dol_is_file($realpathtodocument) ? '' : '</span></strike>').'</strong>';
4415 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtodocument).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4416 if (dol_is_file($realpathtodocument)) {
4417 print ' ';
4418 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtodocument).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4419 } else {
4420 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initpagedocument&token='.newToken().'&format=php&file='.urlencode($pathtocontact).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4421 }
4422 print '<br>';
4423 // Page notes
4424 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForNoteTab").' : <strong class="wordbreak">'.(dol_is_file($realpathtonote) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtonote).(dol_is_file($realpathtonote) ? '' : '</span></strike>').'</strong>';
4425 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtonote).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4426 if (dol_is_file($realpathtonote)) {
4427 print ' ';
4428 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtonote).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4429 } else {
4430 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initpagenote&token='.newToken().'&format=php&file='.urlencode($pathtocontact).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4431 }
4432 print '<br>';
4433 // Page agenda
4434 print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForAgendaTab").' : <strong class="wordbreak">'.(dol_is_file($realpathtoagenda) ? '' : '<strike><span class="opacitymedium">').preg_replace('/^'.strtolower($module).'\//', '', $pathtoagenda).(dol_is_file($realpathtoagenda) ? '' : '</span></strike>').'</strong>';
4435 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&format=php&token='.newToken().'&file='.urlencode($pathtoagenda).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4436 if (dol_is_file($realpathtoagenda)) {
4437 print ' ';
4438 print '<a class="reposition editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtoagenda).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4439 } else {
4440 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&tabobj='.$tabobj.'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initpageagenda&token='.newToken().'&format=php&file='.urlencode($pathtocontact).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
4441 }
4442 print '<br>';
4443 print '<br>';
4444
4445 print '</div>';
4446
4447 print '<br><br><br>';
4448
4449 if (!empty($tmpobject)) {
4450 $reflector = new ReflectionClass($tabobj);
4451 $reflectorproperties = $reflector->getProperties(); // Can also use get_object_vars
4452 $reflectorpropdefault = $reflector->getDefaultProperties(); // Can also use get_object_vars
4453 //$propstat = $reflector->getStaticProperties();
4454 //var_dump($reflectorpropdefault);
4455
4456 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4457 print '<input type="hidden" name="token" value="'.newToken().'">';
4458 print '<input type="hidden" name="action" value="addproperty">';
4459 print '<input type="hidden" name="tab" value="objects">';
4460 print '<input type="hidden" name="page_y" value="">';
4461 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module.($forceddirread ? '@'.$dirread : '')).'">';
4462 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4463
4464 print '<input class="button smallpaddingimp" type="submit" name="regenerateclasssql" value="'.$langs->trans("RegenerateClassAndSql").'">';
4465 print '<br><br>';
4466
4467 $mod = strtolower($module);
4468 $obj = strtolower($tabobj);
4469 $newproperty = dolGetButtonTitle($langs->trans('NewProperty'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.urlencode($module).'&tabobj=createproperty&obj='.urlencode($tabobj));
4470 $nbOfProperties = count($reflectorpropdefault['fields']);
4471
4472 print_barre_liste($langs->trans("ObjectProperties"), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, $nbOfProperties, '', 0, $newproperty, '', 0, 0, 0, 1);
4473
4474 //var_dump($reflectorpropdefault);exit;
4475 print '<!-- Table with properties of object -->'."\n";
4476 print '<div class="div-table-responsive">';
4477 print '<table class="noborder small">';
4478 print '<tr class="liste_titre">';
4479 print '<th class="tdsticky tdstickygray">';
4480 $htmltext = $langs->trans("PropertyDesc").'<br><br><a class="" href="https://wiki.dolibarr.org/index.php/Language_and_development_rules#Table_and_fields_structures" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeExamples").'</a>';
4481 print $form->textwithpicto($langs->trans("Code"), $htmltext, 1, 'help', 'extracss', 0, 3, 'propertyhelp');
4482 print '</th>';
4483 print '<th>';
4484 print $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey"));
4485 print '</th>';
4486 print '<th>'.$form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp').'</th>';
4487 print '<th>'.$form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")).'</th>';
4488 print '<th class="center">'.$form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")).'</th>';
4489 print '<th class="center">'.$langs->trans("DefaultValue").'</th>';
4490 print '<th class="center">'.$langs->trans("DatabaseIndex").'</th>';
4491 print '<th class="center">'.$form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp').'</th>';
4492 print '<th class="right">'.$langs->trans("Position").'</th>';
4493 print '<th class="center">'.$form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp').'</th>';
4494 print '<th class="center">'.$form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp').'</th>';
4495 print '<th class="center">'.$langs->trans("NotEditable").'</th>';
4496 //print '<th class="center">'.$langs->trans("AlwaysEditable").'</th>';
4497 print '<th class="center">'.$form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")).'</th>';
4498 print '<th class="center">'.$form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")).'</th>';
4499 print '<th class="center">'.$langs->trans("CSSClass").'</th>';
4500 print '<th class="center">'.$langs->trans("CSSViewClass").'</th>';
4501 print '<th class="center">'.$langs->trans("CSSListClass").'</th>';
4502 print '<th>'.$langs->trans("KeyForTooltip").'</th>';
4503 print '<th class="center">'.$langs->trans("ShowOnCombobox").'</th>';
4504 //print '<th class="center">'.$langs->trans("Disabled").'</th>';
4505 print '<th>'.$form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")).'</th>';
4506 print '<th>'.$langs->trans("Comment").'</th>';
4507 print '<th class="tdstickyright tdstickyghostwhite"></th>';
4508 print '</tr>';
4509
4510 // We must use $reflectorpropdefault['fields'] to get list of fields because $tmpobject->fields may have been
4511 // modified during the constructor and we want value into head of class before constructor is called.
4512 //$properties = dol_sort_array($tmpobject->fields, 'position');
4513 $properties = dol_sort_array($reflectorpropdefault['fields'], 'position');
4514 if (!empty($properties)) {
4515 // List of existing properties
4516 foreach ($properties as $propkey => $propval) {
4517 /* If from Reflection
4518 if ($propval->class == $tabobj)
4519 {
4520 $propname=$propval->getName();
4521 $comment=$propval->getDocComment();
4522 $type=gettype($tmpobject->$propname);
4523 $default=$propdefault[$propname];
4524 // Discard generic properties
4525 if (in_array($propname, array('element', 'childtables', 'table_element', 'table_element_line', 'class_element_line', 'ismultientitymanaged'))) continue;
4526
4527 // Keep or not lines
4528 if (in_array($propname, array('fk_element', 'lines'))) continue;
4529 }*/
4530
4531 $propname = $propkey;
4532 $proplabel = $propval['label'];
4533 $proptype = $propval['type'];
4534 $proparrayofkeyval = !empty($propval['arrayofkeyval']) ? $propval['arrayofkeyval'] : '';
4535 $propnotnull = !empty($propval['notnull']) ? $propval['notnull'] : '0';
4536 $propdefault = !empty($propval['default']) ? $propval['default'] : '';
4537 $propindex = !empty($propval['index']) ? $propval['index'] : '';
4538 $propforeignkey = !empty($propval['foreignkey']) ? $propval['foreignkey'] : '';
4539 $propposition = $propval['position'];
4540 $propenabled = $propval['enabled'];
4541 $propvisible = $propval['visible'];
4542 $propnoteditable = !empty($propval['noteditable']) ? $propval['noteditable'] : 0;
4543 //$propalwayseditable = !empty($propval['alwayseditable'])?$propval['alwayseditable']:0;
4544 $propsearchall = !empty($propval['searchall']) ? $propval['searchall'] : 0;
4545 $propisameasure = !empty($propval['isameasure']) ? $propval['isameasure'] : 0;
4546 $propcss = !empty($propval['css']) ? $propval['css'] : '';
4547 $propcssview = !empty($propval['cssview']) ? $propval['cssview'] : '';
4548 $propcsslist = !empty($propval['csslist']) ? $propval['csslist'] : '';
4549 $prophelp = !empty($propval['help']) ? $propval['help'] : '';
4550 $propshowoncombobox = !empty($propval['showoncombobox']) ? $propval['showoncombobox'] : 0;
4551 //$propdisabled=$propval['disabled'];
4552 $propvalidate = !empty($propval['validate']) ? $propval['validate'] : 0;
4553 $propcomment = !empty($propval['comment']) ? $propval['comment'] : '';
4554
4555 print '<!-- line for object property -->'."\n";
4556 print '<tr class="oddeven">';
4557
4558 print '<td class="tdsticky tdstickygray">';
4559 print dol_escape_htmltag($propname);
4560 print '</td>';
4561 if ($action == 'editproperty' && $propname == $propertykey) {
4562 print '<td>';
4563 print '<input type="hidden" name="propname" value="'.dol_escape_htmltag($propname).'">';
4564 print '<input name="proplabel" class="maxwidth125" value="'.dol_escape_htmltag($proplabel).'">';
4565 print '</td>';
4566 print '<td class="tdoverflowmax150">';
4567 print '<input name="proptype" class="maxwidth125" value="'.dol_escape_htmltag($proptype).'"></input>';
4568 print '</td>';
4569 print '<td class="tdoverflowmax200">';
4570 print '<textarea name="proparrayofkeyval">';
4571 if (isset($proparrayofkeyval)) {
4572 if (is_array($proparrayofkeyval) || $proparrayofkeyval != '') {
4573 print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
4574 }
4575 }
4576 print '</textarea>';
4577 print '</td>';
4578 print '<td>';
4579 print '<input class="center width50" name="propnotnull" value="'.dol_escape_htmltag($propnotnull).'">';
4580 print '</td>';
4581 print '<td>';
4582 print '<input class="maxwidth50" name="propdefault" value="'.dol_escape_htmltag($propdefault).'">';
4583 print '</td>';
4584 print '<td class="center">';
4585 print '<input class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag($propindex).'">';
4586 print '</td>';
4587 print '<td>';
4588 print '<input class="center maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag($propforeignkey).'">';
4589 print '</td>';
4590 print '<td>';
4591 print '<input class="right width50" name="propposition" value="'.dol_escape_htmltag($propposition).'">';
4592 print '</td>';
4593 print '<td>';
4594 print '<input class="center width75" name="propenabled" value="'.dol_escape_htmltag($propenabled).'">';
4595 print '</td>';
4596 print '<td>';
4597 print '<input class="center width75" name="propvisible" value="'.dol_escape_htmltag($propvisible).'">';
4598 print '</td>';
4599 print '<td>';
4600 print '<input class="center width50" name="propnoteditable" size="2" value="'.dol_escape_htmltag($propnoteditable).'">';
4601 print '</td>';
4602 /*print '<td>';
4603 print '<input class="center" name="propalwayseditable" size="2" value="'.dol_escape_htmltag($propalwayseditable).'">';
4604 print '</td>';*/
4605 print '<td>';
4606 print '<input class="center width50" name="propsearchall" value="'.dol_escape_htmltag($propsearchall).'">';
4607 print '</td>';
4608 print '<td>';
4609 print '<input class="center width50" name="propisameasure" value="'.dol_escape_htmltag($propisameasure).'">';
4610 print '</td>';
4611 print '<td>';
4612 print '<input class="center maxwidth50" name="propcss" value="'.dol_escape_htmltag($propcss).'">';
4613 print '</td>';
4614 print '<td>';
4615 print '<input class="center maxwidth50" name="propcssview" value="'.dol_escape_htmltag($propcssview).'">';
4616 print '</td>';
4617 print '<td>';
4618 print '<input class="center maxwidth50" name="propcsslist" value="'.dol_escape_htmltag($propcsslist).'">';
4619 print '</td>';
4620 print '<td>';
4621 print '<input class="maxwidth100" name="prophelp" value="'.dol_escape_htmltag($prophelp).'">';
4622 print '</td>';
4623 print '<td>';
4624 print '<input class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag($propshowoncombobox).'">';
4625 print '</td>';
4626 print '<td>';
4627 print '<input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag($propvalidate).'">';
4628 print '</td>';
4629 print '<td>';
4630 print '<input class="maxwidth100" name="propcomment" value="'.dol_escape_htmltag($propcomment).'">';
4631 print '</td>';
4632 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
4633 print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Save").'">';
4634 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
4635 print '</td>';
4636 } else {
4637 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($proplabel).'">';
4638 print dol_escape_htmltag($proplabel);
4639 print '</td>';
4640 print '<td class="tdoverflowmax200">';
4641 $pictoType = '';
4642 $matches = array();
4643 if (preg_match('/^varchar/', $proptype, $matches)) {
4644 $pictoType = 'varchar';
4645 } elseif (preg_match('/^integer:/', $proptype, $matches)) {
4646 $pictoType = 'link';
4647 } elseif (strpos($proptype, 'integer') === 0) {
4648 $pictoType = substr($proptype, 0, 3);
4649 } elseif (strpos($proptype, 'timestamp') === 0) {
4650 $pictoType = 'datetime';
4651 } elseif (strpos($proptype, 'real') === 0) {
4652 $pictoType = 'double';
4653 }
4654 print(!empty($pictoType) ? getPictoForType($pictoType) : getPictoForType($proptype)).'<span title="'.dol_escape_htmltag($proptype).'">'.dol_escape_htmltag($proptype).'</span>';
4655 print '</td>';
4656 print '<td class="tdoverflowmax200">';
4657 if ($proparrayofkeyval) {
4658 print '<span title="'.dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE)).'">';
4659 print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
4660 print '</span>';
4661 }
4662 print '</td>';
4663 print '<td class="center">';
4664 print dol_escape_htmltag($propnotnull);
4665 print '</td>';
4666 print '<td>';
4667 print dol_escape_htmltag($propdefault);
4668 print '</td>';
4669 print '<td class="center">';
4670 print $propindex ? '1' : '';
4671 print '</td>';
4672 print '<td class="center">';
4673 print $propforeignkey ? dol_escape_htmltag($propforeignkey) : '';
4674 print '</td>';
4675 print '<td class="right">';
4676 print dol_escape_htmltag($propposition);
4677 print '</td>';
4678 print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
4679 print $propenabled ? dol_escape_htmltag($propenabled) : '';
4680 print '</td>';
4681 // Visibility
4682 print '<td class="center tdoverflowmax100" title="'.($propvisible ? dol_escape_htmltag($propvisible) : '0').'">';
4683 print $propvisible ? dol_escape_htmltag($propvisible) : '0';
4684 print '</td>';
4685 // Readonly
4686 print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
4687 print $propnoteditable ? dol_escape_htmltag($propnoteditable) : '';
4688 print '</td>';
4689 /*print '<td class="center">';
4690 print $propalwayseditable ? dol_escape_htmltag($propalwayseditable) : '';
4691 print '</td>';*/
4692 print '<td class="center">';
4693 print $propsearchall ? '1' : '';
4694 print '</td>';
4695 print '<td class="center">';
4696 print $propisameasure ? dol_escape_htmltag($propisameasure) : '';
4697 print '</td>';
4698 print '<td class="center tdoverflowmax100" title="'.($propcss ? dol_escape_htmltag($propcss) : '').'">';
4699 print $propcss ? dol_escape_htmltag($propcss) : '';
4700 print '</td>';
4701 print '<td class="center tdoverflowmax100" title="'.($propcssview ? dol_escape_htmltag($propcssview) : '').'">';
4702 print $propcssview ? dol_escape_htmltag($propcssview) : '';
4703 print '</td>';
4704 print '<td class="center tdoverflowmax100" title="'.($propcsslist ? dol_escape_htmltag($propcsslist) : '').'">';
4705 print $propcsslist ? dol_escape_htmltag($propcsslist) : '';
4706 print '</td>';
4707 // Key for tooltop
4708 print '<td class="tdoverflowmax150" title="'.($prophelp ? dol_escape_htmltag($prophelp) : '').'">';
4709 print $prophelp ? dol_escape_htmltag($prophelp) : '';
4710 print '</td>';
4711 print '<td class="center">';
4712 print $propshowoncombobox ? dol_escape_htmltag($propshowoncombobox) : '';
4713 print '</td>';
4714 /*print '<td class="center">';
4715 print $propdisabled?$propdisabled:'';
4716 print '</td>';*/
4717 print '<td class="center">';
4718 print $propvalidate ? dol_escape_htmltag($propvalidate) : '';
4719 print '</td>';
4720 print '<td class="tdoverflowmax200">';
4721 print '<span title="'.dol_escape_htmltag($propcomment).'">';
4722 print dol_escape_htmltag($propcomment);
4723 print '</span>';
4724 print '</td>';
4725 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
4726 if ($propname != 'rowid') {
4727 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=editproperty&token='.newToken().'&propertykey='.urlencode($propname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj).'">'.img_edit().'</a>';
4728 print '<a class="reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=deleteproperty&token='.newToken().'&propertykey='.urlencode($propname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj).'">'.img_delete().'</a>';
4729 }
4730 print '</td>';
4731 }
4732 print '</tr>';
4733 }
4734 } else {
4735 if ($tab == 'specifications') {
4736 if ($action != 'editfile' || empty($file)) {
4737 print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
4738 print '<br>';
4739
4740 $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
4741
4742 foreach ($specs as $spec) {
4743 $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
4744 $format = 'asciidoc';
4745 if (preg_match('/\.md$/i', $spec['name'])) {
4746 $format = 'markdown';
4747 }
4748 print '<span class="fa fa-file-o"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4749 print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format='.$format.'&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
4750 print '<br>';
4751 }
4752 } else {
4753 // Use MD or asciidoc
4754
4755 //print $langs->trans("UseAsciiDocFormat").'<br>';
4756
4757 $fullpathoffile = dol_buildpath($file, 0);
4758
4759 $content = file_get_contents($fullpathoffile);
4760
4761 // New module
4762 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4763 print '<input type="hidden" name="token" value="'.newToken().'">';
4764 print '<input type="hidden" name="action" value="savefile">';
4765 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4766 print '<input type="hidden" name="tab" value="'.$tab.'">';
4767 print '<input type="hidden" name="module" value="'.$module.'">';
4768
4769 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
4770 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
4771 print '<br>';
4772 print '<center>';
4773 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4774 print ' &nbsp; ';
4775 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4776 print '</center>';
4777
4778 print '</form>';
4779 }
4780 }
4781 print '<tr><td><span class="warning">'.$langs->trans('Property %s not found in the class. The class was probably not generated by modulebuilder.', $field).'</warning></td></tr>';
4782 }
4783 print '</table>';
4784 print '</div>';
4785
4786 print '</form>';
4787 } else {
4788 print '<span class="warning">'.$langs->trans('Failed to init the object with the new %s (%s)', $tabobj, (string) $db).'</warning>';
4789 }
4790 } catch (Exception $e) {
4791 print 'ee';
4792 print $e->getMessage();
4793 print 'ff';
4794 }
4795 } else {
4796 if (empty($forceddirread)) {
4797 $fullpathoffile = dol_buildpath($file, 0);
4798 } else {
4799 $fullpathoffile = $dirread.'/'.$file;
4800 }
4801
4802 $content = file_get_contents($fullpathoffile);
4803
4804 // New module
4805 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4806 print '<input type="hidden" name="token" value="'.newToken().'">';
4807 print '<input type="hidden" name="action" value="savefile">';
4808 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4809 print '<input type="hidden" name="tab" value="'.$tab.'">';
4810 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4811 print '<input type="hidden" name="module" value="'.$module.($forceddirread ? '@'.$dirread : '').'">';
4812
4813 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
4814 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
4815 print '<br>';
4816 print '<center>';
4817 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4818 print ' &nbsp; ';
4819 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4820 print '</center>';
4821
4822 print '</form>';
4823 }
4824 }
4825
4826 print dol_get_fiche_end(); // Level 3
4827 }
4828
4829 if ($tab == 'dictionaries') {
4830 print '<!-- tab=dictionaries -->'."\n";
4831 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4832
4833 $dicts = $moduleobj->dictionaries;
4834
4835 if ($action == 'deletedict') {
4836 $formconfirm = $form->formconfirm(
4837 $_SERVER["PHP_SELF"].'?dictionnarykey='.urlencode((string) (GETPOSTINT('d