dolibarr 24.0.0-beta
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-2026 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024-2025 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';
50'
51@phan-var-force string $dolibarr_main_document_root
52@phan-var-force string $dolibarr_main_document_root_alt
53';
54require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
55require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
56require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
57require_once DOL_DOCUMENT_ROOT.'/core/lib/modulebuilder.lib.php';
58require_once DOL_DOCUMENT_ROOT.'/modulebuilder/class/NamingContractValidator.class.php';
59require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
60require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
61
62// Load translation files required by the page
63$langs->loadLangs(array("admin", "modulebuilder", "exports", "other", "cron", "errors", "uxdocumentation"));
64
65// GET Parameters
66$action = GETPOST('action', 'aZ09');
67$confirm = GETPOST('confirm', 'alpha');
68$cancel = GETPOST('cancel', 'alpha');
69
70$sortfield = GETPOST('sortfield', 'aZ09comma');
71$sortorder = GETPOST('sortorder', 'aZ09');
72
73$module = (string) GETPOST('module', 'alpha');
74$tab = (string) GETPOST('tab', 'aZ09');
75$tabobj = GETPOST('tabobj', 'alpha');
76$tabdic = GETPOST('tabdic', 'alpha');
77$propertykey = GETPOST('propertykey', 'alpha');
78if (empty($module)) {
79 $module = 'initmodule';
80}
81if (empty($tab)) {
82 $tab = 'description';
83}
84'@phan-var-force string $tab'; // Workaround 'empty()' bug of phan
85if (empty($tabobj)) {
86 $tabobj = 'newobjectifnoobj';
87}
88if (empty($tabdic)) {
89 $tabdic = 'newdicifnodic';
90}
91$file = GETPOST('file', 'alpha');
92$find = GETPOST('find', 'alpha');
93
94$modulename = dol_sanitizeFileName(GETPOST('modulename', 'alpha'));
95$objectname = dol_sanitizeFileName(GETPOST('objectname', 'alpha'));
96$dicname = dol_sanitizeFileName(GETPOST('dicname', 'alpha'));
97$editorname = (string) GETPOST('editorname', 'alpha');
98$editorurl = (string) GETPOST('editorurl', 'alpha');
99$version = (string) GETPOST('version', 'alpha');
100$family = (string) GETPOST('family', 'alpha');
101$picto = (string) GETPOST('idpicto', 'alpha');
102$idmodule = (string) GETPOST('idmodule', 'alpha');
103$format = ''; // Prevent undefined in css tab
104
105// Security check
106if (!isModEnabled('modulebuilder')) {
107 accessforbidden('Module ModuleBuilder not enabled');
108}
109if (!$user->hasRight("modulebuilder", "run")) { // after this test $user->hasRight("modulebuilder", "run") is always true, no need to check it more
110 accessforbidden('ModuleBuilderNotAllowed');
111}
112
113// Dir for custom dirs
114$tmp = explode(',', $dolibarr_main_document_root_alt);
115$dirins = $tmp[0];
116$dirread = $dirins;
117$forceddirread = 0;
118
119$tmpdir = explode('@', $module);
120if (!empty($tmpdir[1])) {
121 $module = $tmpdir[0];
122 $dirread = $tmpdir[1];
123 $forceddirread = 1;
124}
125if (GETPOST('dirins', 'alpha')) {
126 $dirread = $dirins = GETPOST('dirins', 'alpha');
127 $forceddirread = 1;
128}
129
130$FILEFLAG = 'modulebuilder.txt';
131
132$now = dol_now();
133$newmask = 0;
134if (empty($newmask) && getDolGlobalString('MAIN_UMASK')) {
135 $newmask = getDolGlobalString('MAIN_UMASK');
136}
137if (empty($newmask)) { // This should no happen
138 $newmask = '0664';
139}
140
141$result = restrictedArea($user, 'modulebuilder', 0);
142
143$error = 0;
144$param = '';
145
146$form = new Form($db);
147
148// Define $listofmodules
149$dirsrootforscan = array($dirread);
150
151// Add also the core modules into the list of modules to show/edit
152if ($dirread != DOL_DOCUMENT_ROOT && (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2 || getDolGlobalString('MODULEBUILDER_ADD_DOCUMENT_ROOT'))) {
153 $dirsrootforscan[] = DOL_DOCUMENT_ROOT;
154}
155
156// Search modules to edit
157$textforlistofdirs = '<!-- Directory scanned -->'."\n";
158$listofmodules = array();
159'@phan-var-force array<string,array{modulenamewithcase:string,moduledescriptorrelpath:string,moduledescriptorfullpath:string,moduledescriptorrootpath,moduletype?:string}> $listofmodules';
160$i = 0;
161foreach ($dirsrootforscan as $tmpdirread) {
162 $moduletype = 'external';
163 if ($tmpdirread == DOL_DOCUMENT_ROOT) {
164 $moduletype = 'internal';
165 }
166
167 $dirsincustom = dol_dir_list($tmpdirread, 'directories');
168 if (is_array($dirsincustom) && count($dirsincustom) > 0) {
169 foreach ($dirsincustom as $dircustomcursor) {
170 $fullname = $dircustomcursor['fullname'];
171 if (dol_is_file($fullname.'/'.$FILEFLAG)) {
172 // Get real name of module (MyModule instead of mymodule)
173 $dirtoscanrel = basename($fullname).'/core/modules/';
174
175 $descriptorfiles = dol_dir_list(dirname($fullname).'/'.$dirtoscanrel, 'files', 0, 'mod.*\.class\.php$');
176 if (empty($descriptorfiles)) { // If descriptor not found into module dir, we look into main module dir.
177 $dirtoscanrel = 'core/modules/';
178 $descriptorfiles = dol_dir_list($fullname.'/../'.$dirtoscanrel, 'files', 0, 'mod'.strtoupper(basename($fullname)).'\.class\.php$');
179 }
180 $modulenamewithcase = '';
181 $moduledescriptorrelpath = '';
182 $moduledescriptorfullpath = '';
183
184 foreach ($descriptorfiles as $descriptorcursor) {
185 $modulenamewithcase = preg_replace('/^mod/', '', $descriptorcursor['name']);
186 $modulenamewithcase = preg_replace('/\.class\.php$/', '', $modulenamewithcase);
187 $moduledescriptorrelpath = $dirtoscanrel.$descriptorcursor['name'];
188 $moduledescriptorfullpath = $descriptorcursor['fullname'];
189 //var_dump($descriptorcursor);
190 }
191 if ($modulenamewithcase) {
192 $listofmodules[$dircustomcursor['name']] = array(
193 'modulenamewithcase' => $modulenamewithcase,
194 'moduledescriptorrelpath' => $moduledescriptorrelpath,
195 'moduledescriptorfullpath' => $moduledescriptorfullpath,
196 'moduledescriptorrootpath' => $tmpdirread,
197 'moduletype' => $moduletype
198 );
199 }
200 //var_dump($listofmodules);
201 }
202 }
203 }
204
205 if ($forceddirread && empty($listofmodules)) { // $forceddirread is 1 if we forced dir to read with dirins=... or with module=...@mydir
206 $listofmodules[strtolower($module)] = array(
207 'modulenamewithcase' => $module,
208 'moduledescriptorrelpath' => 'notyetimplemented',
209 'moduledescriptorfullpath' => 'notyetimplemented',
210 'moduledescriptorrootpath' => 'notyetimplemented',
211 );
212 }
213
214 // Show description of content
215 $newdircustom = $dirins;
216 if (empty($newdircustom)) {
217 $newdircustom = img_warning();
218 }
219 // If dirread was forced to somewhere else, by using URL
220 // htdocs/modulebuilder/index.php?module=Inventory@/home/ldestailleur/git/dolibarr/htdocs/product
221 if (empty($i)) {
222 $textforlistofdirs .= $langs->trans("DirScanned").' : ';
223 } else {
224 $textforlistofdirs .= ', ';
225 }
226 $textforlistofdirs .= '<strong class="wordbreakimp">'.$tmpdirread.'</strong>';
227 if ($tmpdirread == DOL_DOCUMENT_ROOT) {
228 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
229 $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MAIN_FEATURES_LEVEL"));
230 }
231 if (getDolGlobalString('MODULEBUILDER_ADD_DOCUMENT_ROOT')) {
232 $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MODULEBUILDER_ADD_DOCUMENT_ROOT"));
233 }
234 }
235 $i++;
236}
237
244{
245 $error = error_get_last();
246 if ($error && ($error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR))) {
247 // Handle the fatal error
248 echo "Fatal error occurred: {$error['message']} in {$error['file']} on line {$error['line']}";
249 // If a header was already send, we suppose it is the llx_Header() so we call the llxFooter()
250 if (headers_sent()) {
251 llxFooter();
252 }
253 }
254}
255register_shutdown_function("moduleBuilderShutdownFunction");
256
257
267function getLicenceHeader($user, $langs, $now)
268{
269 $licInfo = $user->getFullName($langs);
270 $emailTabs = str_repeat("\t", (int) (max(0, (31 - mb_strlen($licInfo)) / 4)));
271 $licInfo .= ($user->email ? $emailTabs.'<'.$user->email.'>' : '');
272 $licInfo = dol_print_date($now, '%Y')."\t\t".$licInfo;
273 return $licInfo;
274}
275
276
277/*
278 * Actions
279 */
280
288function modulebuilderValidateGeneratedFile(string $destfile, NamingContract $nc): void
289{
290 $content = file_get_contents($destfile);
291 if ($content === false) {
292 return;
293 }
294 $validator = new StrictNamingContractValidator();
295 $errors = $validator->validateContent($content, $destfile);
296 if (!empty($errors)) {
298 'ModuleBuilder NamingContract validation warning in ' . $destfile . ': '
299 . implode('; ', array_slice($errors, 0, 3)),
300 LOG_WARNING
301 );
302 $safeErrors = array_map('dol_escape_htmltag', array_slice($errors, 0, 5));
303 setEventMessages(implode('<br>', $safeErrors), null, 'warnings');
304 }
305}
306
307if ($dirins && $action == 'initmodule' && $modulename) { // Test on permission already done
308 $modulename = dol_string_nounprintableascii(dol_string_unaccent(ucwords($modulename))); // Force first letter in uppercase
309 $destdir = '/not_set/';
310 $ncModule = new NamingContract($modulename);
311
312 if (preg_match('/[^a-z0-9]/i', $modulename)) {
313 $error++;
314 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
315 }
316
317 if (!$error) {
318 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
319 $destdir = $dirins.'/'.strtolower($modulename);
320
321 $arrayreplacement = [
322 'mymodule' => $ncModule->moduleNameLower,
323 'MyModule' => $ncModule->moduleNameCase,
324 ];
325 $result = dolCopyDir($srcdir, $destdir, '0', 0, $arrayreplacement);
326 //dol_mkdir($destfile);
327 if ($result <= 0) {
328 if ($result < 0) {
329 $error++;
330 $langs->load("errors");
331 setEventMessages($langs->trans("ErrorFailToCopyDir", $srcdir, $destdir), null, 'errors');
332 } else {
333 // $result == 0
334 setEventMessages($langs->trans("AllFilesDidAlreadyExist", $srcdir, $destdir), null, 'warnings');
335 }
336 }
337
338 // Copy last 'html.formsetup.class.php' to backport folder
339 if (getDolGlobalInt('MODULEBUILDER_SUPPORT_COMPATIBILITY_V16')) {
340 $tryToCopyFromSetupClass = true;
341 $backportDest = $destdir .'/backport/v16/core/class';
342 $backportFileSrc = DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
343 $backportFileDest = $backportDest.'/html.formsetup.class.php';
344 $result = dol_mkdir($backportDest);
345
346 if ($result < 0) {
347 $error++;
348 $langs->load("errors");
349 setEventMessages($langs->trans("ErrorFailToCreateDir", $backportDest), null, 'errors');
350 $tryToCopyFromSetupClass = false;
351 }
352
353 if ($tryToCopyFromSetupClass) {
354 $result = dol_copy($backportFileSrc, $backportFileDest);
355 if ($result <= 0) {
356 if ($result < 0) {
357 $error++;
358 $langs->load("errors");
359 setEventMessages($langs->trans("ErrorFailToCopyFile", $backportFileSrc, $backportFileDest), null, 'errors');
360 } else {
361 setEventMessages($langs->trans("FileDidAlreadyExist", $backportFileDest), null, 'warnings');
362 }
363 }
364 }
365 }
366
367 if (getDolGlobalString('MODULEBUILDER_USE_ABOUT')) {
368 dol_delete_file($destdir.'/admin/about.php');
369 }
370
371 // Delete dir and files that can be generated in sub tabs later if we need them (we want a minimal module first)
372 dol_delete_dir_recursive($destdir.'/ajax');
373 dol_delete_dir_recursive($destdir.'/build/doxygen');
374 dol_delete_dir_recursive($destdir.'/core/modules/mailings');
375 dol_delete_dir_recursive($destdir.'/core/modules/'.strtolower($modulename));
376 dol_delete_dir_recursive($destdir.'/core/tpl');
377 dol_delete_dir_recursive($destdir.'/core/triggers');
378 dol_delete_dir_recursive($destdir.'/doc');
379 //dol_delete_dir_recursive($destdir.'/.tx');
380 dol_delete_dir_recursive($destdir.'/core/boxes');
381
382 dol_delete_file($destdir.'/admin/myobject_extrafields.php');
383
384 dol_delete_file($destdir.'/class/actions_'.strtolower($modulename).'.class.php');
385 dol_delete_file($destdir.'/class/api_'.strtolower($modulename).'.class.php');
386
387 dol_delete_file($destdir.'/css/'.strtolower($modulename).'.css.php');
388
389 dol_delete_file($destdir.'/js/'.strtolower($modulename).'.js.php');
390
391 dol_delete_file($destdir.'/scripts/'.strtolower($modulename).'.php');
392
393 dol_delete_file($destdir.'/sql/data.sql');
394 dol_delete_file($destdir.'/sql/update_x.x.x-y.y.y.sql');
395
396 // Delete some files related to Object (because the previous dolCopyDir has copied everything)
397 dol_delete_file($destdir.'/myobject_card.php');
398 dol_delete_file($destdir.'/myobject_contact.php');
399 dol_delete_file($destdir.'/myobject_note.php');
400 dol_delete_file($destdir.'/myobject_document.php');
401 dol_delete_file($destdir.'/myobject_agenda.php');
402 dol_delete_file($destdir.'/myobject_list.php');
403 dol_delete_file($destdir.'/lib/'.strtolower($modulename).'_myobject.lib.php');
404 dol_delete_file($destdir.'/test/phpunit/functional/'.$modulename.'FunctionalTest.php');
405 dol_delete_file($destdir.'/test/phpunit/MyObjectTest.php');
406 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.sql');
407 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.sql');
408 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.key.sql');
409 dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.key.sql');
410 dol_delete_file($destdir.'/class/myobject.class.php');
411 dol_delete_file($destdir.'/class/myobjectstats.class.php');
412
413 dol_delete_dir($destdir.'/class', 1);
414 dol_delete_dir($destdir.'/css', 1);
415 dol_delete_dir($destdir.'/js', 1);
416 dol_delete_dir($destdir.'/scripts', 1);
417 dol_delete_dir($destdir.'/sql', 1);
418 dol_delete_dir($destdir.'/test/phpunit/functionnal', 1);
419 dol_delete_dir($destdir.'/test/phpunit', 1);
420 dol_delete_dir($destdir.'/test', 1);
421 }
422
423 // Edit PHP files
424 if (!$error) {
425 $listofphpfilestoedit = dol_dir_list($destdir, 'files', 1, '\.(php|MD|js|sql|txt|xml|lang)$', '', 'fullname', SORT_ASC, 0, 1);
426
427 $licInfo = getLicenceHeader($user, $langs, $now);
428 foreach ($listofphpfilestoedit as $phpfileval) {
429 //var_dump($phpfileval['fullname']);
430 $arrayreplacement = array_merge(
431 $ncModule->getSubstitutionMap(),
432 [
433 'htdocs/modulebuilder/template' => $ncModule->moduleNameLower,
434 '---Put here your own copyright and developer email---' => $licInfo,
435 '---Replace with your own copyright and developer email---' => $licInfo,
436 'Editor name' => $editorname,
437 'https://www.example.com' => $editorurl,
438 '$this->version = \'1.0\'' => '$this->version = \'' . $version . '\'',
439 '$this->picto = \'generic\';' => (empty($picto)) ? '$this->picto = \'generic\'' : '$this->picto = \'' . $picto . '\';',
440 'modulefamily' => $family,
441 // Key '500000' would be cast to int(500000) by PHP, then renumbered to 0 by
442 // array_merge — causing str_replace to search for '0' instead of '500000'.
443 // Use a string key that matches the exact assignment line to avoid this.
444 '$this->numero = 500000' => '$this->numero = '.$idmodule,
445 ]
446 );
447
448 if (getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')) {
449 $arrayreplacement['---Replace with your own copyright and developer email---'] = dol_print_date($now, '%Y')."\t\t" . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR');
450 }
451
452 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
453 $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); // @phpstan-ignore-line
454 //var_dump($result);
455 if ($result < 0) {
456 setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
457 }
458 }
459
460 if (getDolGlobalString('MODULEBUILDER_SPECIFIC_README')) {
461 setEventMessages($langs->trans("ContentOfREADMECustomized"), null, 'warnings');
462 dol_delete_file($destdir.'/README.md');
463 file_put_contents($destdir.'/README.md', getDolGlobalString("MODULEBUILDER_SPECIFIC_README"));
464 dolChmod($destdir.'/README.md');
465 }
466 // for create file to add properties
467 // file_put_contents($destdir.'/'.strtolower($modulename).'propertycard.php','');
468 // $srcFileCard = DOL_DOCUMENT_ROOT.'/modulebuilder/card.php';
469 // $destFileCard = $dirins.'/'.strtolower($modulename).'/template/card.php';
470 // dol_copy($srcFileCard, $destdir.'/'.strtolower($modulename).'propertycard.php', '0',1, $arrayreplacement);
471 }
472
473 if (!$error) {
474 setEventMessages($langs->trans('ModuleInitialized', $destdir), null);
475 $module = $modulename;
476
477 clearstatcache(true);
478 if (function_exists('opcache_invalidate')) {
479 opcache_reset(); // remove the include cache hell !
480 }
481
482 header("Location: ".$_SERVER["PHP_SELF"].'?module='.$modulename);
483 exit;
484 }
485}
486
487$destdir = '/not_set/'; // Initialize (for static analysis)
488$destfile = '/not_set/'; // Initialize (for static analysis)
489$srcfile = '/not_set/'; // Initialize (for static analysis)
490
491// init API, PHPUnit
492if ($dirins && in_array($action, array('initapi', 'initphpunit', 'initpagecontact', 'initpagedocument', 'initpagenote', 'initpageagenda')) && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
493 $modulename = ucfirst($module); // Force first letter in uppercase
494 $objectname = $tabobj;
495 $varnametoupdate = '';
496 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
497 $destdir = $dirins.'/'.strtolower($module);
498
499 // Get list of existing objects
500 $objects = dolGetListOfObjectClasses($destdir);
501
502
503 if ($action == 'initapi') { // Test on permission already done
504 if (file_exists($dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php')) {
505 $result = dol_copy(DOL_DOCUMENT_ROOT.'/modulebuilder/template/class/api_mymodule.class.php', $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php', '0', 1);
506 }
507 dol_mkdir($dirins.'/'.strtolower($module).'/class');
508 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
509 $srcfile = $srcdir.'/class/api_mymodule.class.php';
510 $destfile = $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php';
511 } elseif ($action == 'initphpunit') { // Test on permission already done
512 dol_mkdir($dirins.'/'.strtolower($module).'/test/phpunit');
513 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
514 $srcfile = $srcdir.'/test/phpunit/MyObjectTest.php';
515 $destfile = $dirins.'/'.strtolower($module).'/test/phpunit/'.strtolower($objectname).'Test.php';
516 } elseif ($action == 'initpagecontact') { // Test on permission already done
517 dol_mkdir($dirins.'/'.strtolower($module));
518 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
519 $srcfile = $srcdir.'/myobject_contact.php';
520 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_contact.php';
521 $varnametoupdate = 'showtabofpagecontact';
522 } elseif ($action == 'initpagedocument') { // Test on permission already done
523 dol_mkdir($dirins.'/'.strtolower($module));
524 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
525 $srcfile = $srcdir.'/myobject_document.php';
526 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_document.php';
527 $varnametoupdate = 'showtabofpagedocument';
528 } elseif ($action == 'initpagenote') { // Test on permission already done
529 dol_mkdir($dirins.'/'.strtolower($module));
530 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
531 $srcfile = $srcdir.'/myobject_note.php';
532 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_note.php';
533 $varnametoupdate = 'showtabofpagenote';
534 } elseif ($action == 'initpageagenda') { // Test on permission already done
535 dol_mkdir($dirins.'/'.strtolower($module));
536 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
537 $srcfile = $srcdir.'/myobject_agenda.php';
538 $destfile = $dirins.'/'.strtolower($module).'/'.strtolower($objectname).'_agenda.php';
539 $varnametoupdate = 'showtabofpageagenda';
540 }
541
542 if (!file_exists($destfile)) {
543 $result = dol_copy($srcfile, $destfile, '0', 0);
544 }
545
546 if ($result > 0) {
547 //var_dump($phpfileval['fullname']);
548 try {
549 $ncApiObj = new NamingContract($modulename, $objectname);
550 } catch (\InvalidArgumentException $e) {
551 $error++;
552 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
553 $ncApiObj = null;
554 }
555
556 if (!$error && $ncApiObj !== null) {
557 $arrayreplacement = array_merge(
558 $ncApiObj->getSubstitutionMap(),
559 [
560 'htdocs/modulebuilder/template' => $ncApiObj->moduleNameLower,
561 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now),
562 ]
563 );
564
565 if ($action == 'initapi') { // Test on permission already done
566 if (count($objects) >= 1) {
567 addObjectsToApiFile($srcfile, $destfile, $objects, $modulename);
568 }
569 // Fix PHPDoc header and class-declaration residuals left by addObjectsToApiFile.
570 // 'MYOBJECT' (uppercase) is excluded to preserve the /* BEGIN MODULEBUILDER API MYOBJECT */
571 // placeholder that addObjectsToApiFile keeps for future object additions.
572 $headerFix = $arrayreplacement;
573 unset($headerFix['MYOBJECT']);
574 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
575 dolReplaceInFile($destfile, $headerFix);
576 modulebuilderValidateGeneratedFile($destfile, $ncApiObj);
577 } else {
578 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
579 dolReplaceInFile($destfile, $arrayreplacement);
580 modulebuilderValidateGeneratedFile($destfile, $ncApiObj);
581 }
582 }
583
584 if ($varnametoupdate) {
585 // Now we update the object file to set $$varnametoupdate to 1
586 $srcfile = $dirins.'/'.strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php';
587 $arrayreplacement = array('/\$'.preg_quote($varnametoupdate, '/').' = 0;/' => '$'.$varnametoupdate.' = 1;');
588 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
589 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
590 }
591 } else {
592 $langs->load("errors");
593 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
594 }
595}
596
597
598// init ExtraFields
599if ($dirins && $action == 'initsqlextrafields' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
600 $modulename = ucfirst($module); // Force first letter in uppercase
601 $objectname = $tabobj;
602
603 dol_mkdir($dirins.'/'.strtolower($module).'/sql');
604 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
605 $srcfile1 = $srcdir.'/sql/llx_mymodule_myobject_extrafields.sql';
606 $destfile1 = $dirins.'/'.strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql';
607 $result1 = dol_copy($srcfile1, $destfile1, '0', 0);
608 $srcfile2 = $srcdir.'/sql/llx_mymodule_myobject_extrafields.key.sql';
609 $destfile2 = $dirins.'/'.strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql';
610 $result2 = dol_copy($srcfile2, $destfile2, '0', 0);
611
612 if ($result1 > 0 && $result2 > 0) {
613 $modulename = ucfirst($module); // Force first letter in uppercase
614
615 //var_dump($phpfileval['fullname']);
616 try {
617 $ncSqlObj = new NamingContract($modulename, $objectname);
618 } catch (\InvalidArgumentException $e) {
619 $error++;
620 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
621 $ncSqlObj = null;
622 }
623
624 if (!$error && $ncSqlObj !== null) {
625 $arrayreplacement = array_merge(
626 $ncSqlObj->getSubstitutionMap(),
627 [
628 'htdocs/modulebuilder/template' => $ncSqlObj->moduleNameLower,
629 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now),
630 ]
631 );
632
633 dolReplaceInFile($destfile1, $arrayreplacement);
634 dolReplaceInFile($destfile2, $arrayreplacement);
635 modulebuilderValidateGeneratedFile($destfile1, $ncSqlObj);
636 modulebuilderValidateGeneratedFile($destfile2, $ncSqlObj);
637 }
638 } else {
639 $langs->load("errors");
640 if ($result1 <= 0) {
641 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile1), null, 'errors');
642 }
643 if ($result2 <= 0) {
644 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile2), null, 'errors');
645 }
646 }
647
648 // Now we update the object file to set $this->isextrafieldmanaged to 1
649 $srcfile = $dirins.'/'.strtolower($module).'/class/'.strtolower($objectname).'.class.php';
650 $arrayreplacement = array('/\$this->isextrafieldmanaged = 0;/' => '$this->isextrafieldmanaged = 1;');
651 $arrayreplacement = array('/\$isextrafieldmanaged = 0;/' => '$isextrafieldmanaged = 1;');
652 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
653}
654
655
656// init Hook
657if ($dirins && $action == 'inithook' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
658 dol_mkdir($dirins.'/'.strtolower($module).'/class');
659 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
660 $srcfile = $srcdir.'/class/actions_mymodule.class.php';
661 $destfile = $dirins.'/'.strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
662 $result = dol_copy($srcfile, $destfile, '0', 0);
663
664 if ($result > 0) {
665 $modulename = ucfirst($module); // Force first letter in uppercase
666
667 //var_dump($phpfileval['fullname']);
668 $arrayreplacement = array(
669 'mymodule' => strtolower($modulename),
670 'MyModule' => $modulename,
671 'MYMODULE' => strtoupper($modulename),
672 'My module' => $modulename,
673 'my module' => $modulename,
674 'Mon module' => $modulename,
675 'mon module' => $modulename,
676 'htdocs/modulebuilder/template' => strtolower($modulename),
677 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
678 );
679
680 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
681 dolReplaceInFile($destfile, $arrayreplacement);
682 } else {
683 $langs->load("errors");
684 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
685 }
686}
687
688
689// init Trigger
690if ($dirins && $action == 'inittrigger' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
691 dol_mkdir($dirins.'/'.strtolower($module).'/core/triggers');
692 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
693 $srcfile = $srcdir.'/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php';
694 $destfile = $dirins.'/'.strtolower($module).'/core/triggers/interface_99_mod'.$module.'_'.$module.'Triggers.class.php';
695 $result = dol_copy($srcfile, $destfile, '0', 0);
696
697 if ($result > 0) {
698 $modulename = ucfirst($module); // Force first letter in uppercase
699
700 //var_dump($phpfileval['fullname']);
701 $arrayreplacement = array(
702 'mymodule' => strtolower($modulename),
703 'MyModule' => $modulename,
704 'MYMODULE' => strtoupper($modulename),
705 'My module' => $modulename,
706 'my module' => $modulename,
707 'Mon module' => $modulename,
708 'mon module' => $modulename,
709 'htdocs/modulebuilder/template' => strtolower($modulename),
710 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
711 );
712
713 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
714 dolReplaceInFile($destfile, $arrayreplacement);
715 } else {
716 $langs->load("errors");
717 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
718 }
719}
720
721
722// init Widget
723if ($dirins && $action == 'initwidget' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
724 dol_mkdir($dirins.'/'.strtolower($module).'/core/boxes');
725 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
726 $srcfile = $srcdir.'/core/boxes/mymodulewidget1.php';
727 $destfile = $dirins.'/'.strtolower($module).'/core/boxes/'.strtolower($module).'widget1.php';
728 $result = dol_copy($srcfile, $destfile, '0', 0);
729
730 if ($result > 0) {
731 $modulename = ucfirst($module); // Force first letter in uppercase
732
733 //var_dump($phpfileval['fullname']);
734 $arrayreplacement = array(
735 'mymodule' => strtolower($modulename),
736 'MyModule' => $modulename,
737 'MYMODULE' => strtoupper($modulename),
738 'My module' => $modulename,
739 'my module' => $modulename,
740 'Mon module' => $modulename,
741 'mon module' => $modulename,
742 'htdocs/modulebuilder/template' => strtolower($modulename),
743 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
744 );
745
746 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
747 dolReplaceInFile($destfile, $arrayreplacement);
748 } else {
749 $langs->load("errors");
750 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
751 }
752}
753
754
755// init EmailSelector
756if ($dirins && $action == 'initemailing' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
757 dol_mkdir($dirins.'/'.strtolower($module).'/core/modules/mailings');
758 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
759 $srcfile = $srcdir.'/core/modules/mailings/mailing_mymodule_selector1.modules.php';
760 $destfile = $dirins.'/'.strtolower($module).'/core/modules/mailings/mailing_'.strtolower($module).'_selector1.modules.php';
761 $result = dol_copy($srcfile, $destfile, '0', 0);
762
763 if ($result > 0) {
764 $modulename = ucfirst($module); // Force first letter in uppercase
765
766 //var_dump($phpfileval['fullname']);
767 $arrayreplacement = array(
768 'mymodule' => strtolower($modulename),
769 'MyModule' => $modulename,
770 'MYMODULE' => strtoupper($modulename),
771 'My module' => $modulename,
772 'my module' => $modulename,
773 'Mon module' => $modulename,
774 'mon module' => $modulename,
775 'htdocs/modulebuilder/template' => strtolower($modulename),
776 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
777 );
778
779 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
780 dolReplaceInFile($destfile, $arrayreplacement);
781 } else {
782 $langs->load("errors");
783 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
784 }
785}
786
787
788// init CSS
789if ($dirins && $action == 'initcss' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
790 dol_mkdir($dirins.'/'.strtolower($module).'/css');
791 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
792 $srcfile = $srcdir.'/css/mymodule.css.php';
793 $destfile = $dirins.'/'.strtolower($module).'/css/'.strtolower($module).'.css.php';
794 $result = dol_copy($srcfile, $destfile, '0', 0);
795
796 if ($result > 0) {
797 $modulename = ucfirst($module); // Force first letter in uppercase
798
799 //var_dump($phpfileval['fullname']);
800 $arrayreplacement = array(
801 'mymodule' => strtolower($modulename),
802 'MyModule' => $modulename,
803 'MYMODULE' => strtoupper($modulename),
804 'My module' => $modulename,
805 'my module' => $modulename,
806 'Mon module' => $modulename,
807 'mon module' => $modulename,
808 'htdocs/modulebuilder/template' => strtolower($modulename),
809 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
810 );
811
812 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
813 dolReplaceInFile($destfile, $arrayreplacement);
814
815 // Update descriptor file to uncomment file
816 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
817 $arrayreplacement = array('/\/\/\s*\''.preg_quote('/'.strtolower($module).'/css/'.strtolower($module).'.css.php', '/').'\'/' => '\'/'.strtolower($module).'/css/'.strtolower($module).'.css.php\'');
818 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
819 } else {
820 $langs->load("errors");
821 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
822 }
823}
824
825
826// init JS
827if ($dirins && $action == 'initjs' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
828 dol_mkdir($dirins.'/'.strtolower($module).'/js');
829 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
830 $srcfile = $srcdir.'/js/mymodule.js.php';
831 $destfile = $dirins.'/'.strtolower($module).'/js/'.strtolower($module).'.js.php';
832 $result = dol_copy($srcfile, $destfile, '0', 0);
833
834 if ($result > 0) {
835 $modulename = ucfirst($module); // Force first letter in uppercase
836
837 //var_dump($phpfileval['fullname']);
838 $arrayreplacement = array(
839 'mymodule' => strtolower($modulename),
840 'MyModule' => $modulename,
841 'MYMODULE' => strtoupper($modulename),
842 'My module' => $modulename,
843 'my module' => $modulename,
844 'Mon module' => $modulename,
845 'mon module' => $modulename,
846 'htdocs/modulebuilder/template' => strtolower($modulename),
847 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
848 );
849
850 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
851 dolReplaceInFile($destfile, $arrayreplacement);
852
853 // Update descriptor file to uncomment file
854 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
855 $arrayreplacement = array('/\/\/\s*\''.preg_quote('/'.strtolower($module).'/js/'.strtolower($module).'.js.php', '/').'\'/' => '\'/'.strtolower($module).'/js/'.strtolower($module).'.js.php\'');
856 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
857 } else {
858 $langs->load("errors");
859 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
860 }
861}
862
863
864// init CLI
865if ($dirins && $action == 'initcli' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
866 dol_mkdir($dirins.'/'.strtolower($module).'/scripts');
867 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
868 $srcfile = $srcdir.'/scripts/mymodule.php';
869 $destfile = $dirins.'/'.strtolower($module).'/scripts/'.strtolower($module).'.php';
870 $result = dol_copy($srcfile, $destfile, '0', 0);
871
872 if ($result > 0) {
873 $modulename = ucfirst($module); // Force first letter in uppercase
874
875 //var_dump($phpfileval['fullname']);
876 $arrayreplacement = array(
877 'mymodule' => strtolower($modulename),
878 'MyModule' => $modulename,
879 'MYMODULE' => strtoupper($modulename),
880 'My module' => $modulename,
881 'my module' => $modulename,
882 'Mon module' => $modulename,
883 'mon module' => $modulename,
884 'htdocs/modulebuilder/template' => strtolower($modulename),
885 '__MYCOMPANY_NAME__' => $mysoc->name,
886 '__KEYWORDS__' => $modulename,
887 '__USER_FULLNAME__' => $user->getFullName($langs),
888 '__USER_EMAIL__' => $user->email,
889 '__YYYY-MM-DD__' => dol_print_date($now, 'dayrfc'),
890 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
891 );
892
893 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
894 dolReplaceInFile($destfile, $arrayreplacement);
895 } else {
896 $langs->load("errors");
897 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
898 }
899}
900
901
902$moduledescriptorfile = '/not_set/';
903$modulelowercase = null;
904
905// init Doc
906if ($dirins && $action == 'initdoc' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
907 dol_mkdir($dirins.'/'.strtolower($module).'/doc');
908 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
909 $srcfile = $srcdir.'/doc/Documentation.asciidoc';
910 $destfile = $dirins.'/'.strtolower($module).'/doc/Documentation.asciidoc';
911 $result = dol_copy($srcfile, $destfile, '0', 0);
912
913 if ($result > 0) {
914 $modulename = ucfirst($module); // Force first letter in uppercase
915 $modulelowercase = strtolower($module);
916
917 //var_dump($phpfileval['fullname']);
918 $arrayreplacement = array(
919 'mymodule' => strtolower($modulename),
920 'MyModule' => $modulename,
921 'MYMODULE' => strtoupper($modulename),
922 'My module' => $modulename,
923 'my module' => $modulename,
924 'Mon module' => $modulename,
925 'mon module' => $modulename,
926 'htdocs/modulebuilder/template' => strtolower($modulename),
927 '__MYCOMPANY_NAME__' => $mysoc->name,
928 '__KEYWORDS__' => $modulename,
929 '__USER_FULLNAME__' => $user->getFullName($langs),
930 '__USER_EMAIL__' => $user->email,
931 '__YYYY-MM-DD__' => dol_print_date($now, 'dayrfc'),
932 '---Replace with your own copyright and developer email---' => getLicenceHeader($user, $langs, $now)
933 );
934
935 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
936 dolReplaceInFile($destfile, $arrayreplacement);
937
938 // add table of properties
939 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
940 $destdir = $dirins.'/'.strtolower($module);
941 $objects = dolGetListOfObjectClasses($destdir);
942 foreach ($objects as $path => $obj) {
943 writePropsInAsciiDoc($path, $obj, $destfile);
944 }
945
946 // add table of permissions
947 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
948 writePermsInAsciiDoc($moduledescriptorfile, $destfile);
949
950 // add api urls if file exist
951 if (file_exists($dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php')) {
952 $apiFile = $dirins.'/'.strtolower($module).'/class/api_'.strtolower($module).'.class.php';
953 writeApiUrlsInDoc($apiFile, $destfile);
954 }
955
956 // add ChangeLog in Doc
957 if (file_exists($dirins.'/'.strtolower($module).'/ChangeLog.md')) {
958 $changeLog = $dirins.'/'.strtolower($module).'/ChangeLog.md';
959 $string = file_get_contents($changeLog);
960
961 $replace = explode("\n", $string);
962 $strreplace = array();
963 foreach ($replace as $line) {
964 if ($line === '') {
965 continue;
966 }
967 if (strpos($line, '##') !== false) {
968 $strreplace[$line] = str_replace('##', '', $line);
969 } else {
970 $strreplace[$line] = $line;
971 }
972 }
973 $stringLog = implode("\n", $strreplace);
974 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
975 dolReplaceInFile($destfile, array('//include::ChangeLog.md[]' => '','__CHANGELOG__' => $stringLog));
976 }
977
978 // Delete old documentation files
979 $FILENAMEDOC = $modulelowercase.'.html';
980 $FILENAMEDOCPDF = $modulelowercase.'.pdf';
981 $outputfiledoc = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOC;
982 $outputfiledocurl = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOC;
983 $outputfiledocpdf = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOCPDF;
984 $outputfiledocurlpdf = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOCPDF;
985
986 dol_delete_file($outputfiledoc, 0, 0, 0, null, false, 0);
987 dol_delete_file($outputfiledocpdf, 0, 0, 0, null, false, 0);
988 } else {
989 $langs->load("errors");
990 setEventMessages($langs->trans('ErrorFailToCreateFile', $destfile), null, 'errors');
991 }
992}
993
994
995// add Language
996if ($dirins && $action == 'addlanguage' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
997 $newlangcode = GETPOST('newlangcode', 'aZ09');
998
999 if ($newlangcode) {
1000 $modulelowercase = strtolower($module);
1001
1002 // Dir for module
1003 $diroflang = dol_buildpath($modulelowercase, 0);
1004
1005 if ($diroflang == $dolibarr_main_document_root.'/'.$modulelowercase) {
1006 // This is not a custom module, we force diroflang to htdocs root
1007 $diroflang = $dolibarr_main_document_root;
1008
1009 $srcfile = $diroflang.'/langs/en_US/'.$modulelowercase.'.lang';
1010 $destfile = $diroflang.'/langs/'.$newlangcode.'/'.$modulelowercase.'.lang';
1011
1012 $result = dol_copy($srcfile, $destfile, '0', 0);
1013 if ($result < 0) {
1014 setEventMessages($langs->trans("ErrorFailToCopyFile", $srcfile, $destfile), null, 'errors');
1015 }
1016 } else {
1017 $srcdir = $diroflang.'/langs/en_US';
1018 $srcfile = $diroflang.'/langs/en_US/'.$modulelowercase.'.lang';
1019 $destdir = $diroflang.'/langs/'.$newlangcode;
1020
1021 $arrayofreplacement = array();
1022 if (!dol_is_dir($srcdir) || !dol_is_file($srcfile)) {
1023 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template/langs/en_US';
1024 $arrayofreplacement = array('mymodule' => $modulelowercase);
1025 }
1026 $result = dolCopyDir($srcdir, $destdir, '0', 0, $arrayofreplacement);
1027 }
1028 } else {
1029 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Language")), null, 'errors');
1030 }
1031}
1032
1033
1034// Remove/delete File
1035if ($dirins && $action == 'confirm_removefile' && !empty($module) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
1036 $objectname = $tabobj;
1037 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1038 $destdir = $dirins.'/'.strtolower($module);
1039
1040 $relativefilename = dol_sanitizePathName(GETPOST('file', 'restricthtml'));
1041
1042 // Now we delete the file
1043 if ($relativefilename) {
1044 $dirnametodelete = dirname($relativefilename);
1045 $filetodelete = $dirins.'/'.$relativefilename;
1046 $dirtodelete = $dirins.'/'.$dirnametodelete;
1047
1048 // Get list of existing objects
1049 $objects = dolGetListOfObjectClasses($destdir);
1050
1051 $keyofobjecttodelete = array_search($objectname, $objects);
1052 if ($keyofobjecttodelete !== false) {
1053 unset($objects[$keyofobjecttodelete]);
1054 }
1055
1056 // Delete or modify the file
1057 if (strpos($relativefilename, 'api') !== false) {
1058 $file_api = $destdir.'/class/api_'.strtolower($module).'.class.php';
1059
1060 $removeFile = removeObjectFromApiFile($file_api, $objects, $objectname);
1061
1062 if (count($objects) == 0) {
1063 $result = dol_delete_file($filetodelete);
1064 }
1065
1066 if ($removeFile) {
1067 setEventMessages($langs->trans("ApiObjectDeleted"), null);
1068 }
1069 } else {
1070 $result = dol_delete_file($filetodelete);
1071 }
1072
1073 if (!$result) {
1074 setEventMessages($langs->trans("ErrorFailToDeleteFile", basename($filetodelete)), null, 'errors');
1075 } else {
1076 // If we delete a .sql file, we delete also the other .sql file
1077 if (preg_match('/\.sql$/', $relativefilename)) {
1078 if (preg_match('/\.key\.sql$/', $relativefilename)) {
1079 $relativefilename = preg_replace('/\.key\.sql$/', '.sql', $relativefilename);
1080 $filetodelete = $dirins.'/'.$relativefilename;
1081 $result = dol_delete_file($filetodelete);
1082 } elseif (preg_match('/\.sql$/', $relativefilename)) {
1083 $relativefilename = preg_replace('/\.sql$/', '.key.sql', $relativefilename);
1084 $filetodelete = $dirins.'/'.$relativefilename;
1085 $result = dol_delete_file($filetodelete);
1086 }
1087 }
1088
1089 if (dol_is_dir_empty($dirtodelete)) {
1090 dol_delete_dir($dirtodelete);
1091 }
1092
1093 // Update descriptor file to comment file
1094 if (in_array($tab, array('css', 'js'))) {
1095 $srcfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1096 $arrayreplacement = array('/^\s*\''.preg_quote('/'.$relativefilename, '/').'\',*/m' => ' // \'/'.$relativefilename.'\',');
1097 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1098 }
1099
1100 if (preg_match('/_extrafields/', $relativefilename)) {
1101 // Now we update the object file to set $isextrafieldmanaged to 0
1102 $srcfile = $dirins.'/'.strtolower($module).'/class/'.strtolower($objectname).'.class.php';
1103 $arrayreplacement = array('/\$isextrafieldmanaged = 1;/' => '$isextrafieldmanaged = 0;');
1104 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1105 }
1106
1107 // Now we update the lib file to set $showtabofpagexxx to 0
1108 $varnametoupdate = '';
1109 $reg = array();
1110 if (preg_match('/_([a-z]+)\.php$/', $relativefilename, $reg)) {
1111 $varnametoupdate = 'showtabofpage'.$reg[1];
1112 }
1113 if ($varnametoupdate) {
1114 $srcfile = $dirins.'/'.strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php';
1115 $arrayreplacement = array('/\$'.preg_quote($varnametoupdate, '/').' = 1;/' => '$'.preg_quote($varnametoupdate, '/').' = 0;');
1116 dolReplaceInFile($srcfile, $arrayreplacement, '', '0', 0, 1);
1117 }
1118 }
1119 }
1120}
1121
1122// Init an object
1123if ($dirins && $action == 'initobject' && $module && $objectname) { // Test on permission already done
1124 $warning = 0;
1125
1126 $objectname = dol_string_nounprintableascii(dol_string_unaccent(ucwords($objectname))); // Force first letter in uppercase
1127
1128 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1129 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1130
1131 if (preg_match('/[^a-z0-9]/i', $objectname)) {
1132 $error++;
1133 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1134 $tabobj = 'newobject';
1135 }
1136 if (class_exists($objectname)) {
1137 // TODO Add a more efficient detection. Scan disk ?
1138 $error++;
1139 setEventMessages($langs->trans("AnObjectWithThisClassNameAlreadyExists"), null, 'errors');
1140 $tabobj = 'newobject';
1141 }
1142
1143 try {
1144 $ncObj = new NamingContract($module, $objectname);
1145 } catch (\InvalidArgumentException $e) {
1146 $error++;
1147 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1148 $ncObj = null;
1149 }
1150
1151 $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
1152 $destdir = $dirins.'/'.strtolower($module);
1153
1154 // Optional tabs selected by user, and detection of an already generated object (for idempotence warning)
1155 $enabledtabs = filterEnabledTabs(GETPOST('enabledtab', 'array'), getModuleBuilderObjectTabs());
1156 $objectalreadyexists = dol_is_file($destdir.'/class/'.strtolower($objectname).'.class.php');
1157
1158 // The dir was not created by init
1159 dol_mkdir($destdir.'/class');
1160 dol_mkdir($destdir.'/img');
1161 dol_mkdir($destdir.'/lib');
1162 dol_mkdir($destdir.'/scripts');
1163 dol_mkdir($destdir.'/sql');
1164 dol_mkdir($destdir.'/ajax');
1165 dol_mkdir($destdir.'/stats');
1166
1167 // Scan dir class to find if an object with the same name already exists.
1168 if (!$error) {
1169 $dirlist = dol_dir_list($destdir.'/class', 'files', 0, '\.txt$');
1170 $alreadyfound = false;
1171 foreach ($dirlist as $key => $val) {
1172 $filefound = preg_replace('/\.txt$/', '', $val['name']);
1173 if (strtolower($objectname) == strtolower($filefound) && $objectname != $filefound) {
1174 $alreadyfound = true;
1175 $error++;
1176 setEventMessages($langs->trans("AnObjectAlreadyExistWithThisNameAndDiffCase"), null, 'errors');
1177 break;
1178 }
1179 }
1180 }
1181
1182 // If we must reuse an existing table for properties, define $stringforproperties
1183 // Generate class file from the table
1184 $stringforproperties = '';
1185 $tablename = GETPOST('initfromtablename', 'alpha');
1186 if ($tablename) {
1187 $_results = $db->DDLDescTable($tablename);
1188 if (empty($_results)) {
1189 $error++;
1190 $langs->load("errors");
1191 setEventMessages($langs->trans("ErrorTableNotFound", $tablename), null, 'errors');
1192 } else {
1220 /*public $fields=array(
1221 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'index' => 1, 'position' => 1, 'comment' => 'Id'),
1222 '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'),
1223 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'default' => 1, 'notnull' => 1, 'index' => 1, 'position' => 20),
1224 'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'position' => 30, 'searchall' => 1, 'css' => 'minwidth200', 'help' => 'Help text', 'alwayseditable' => '1'),
1225 'amount' => array('type' => 'double(24,8)', 'label' => 'Amount', 'enabled' => 1, 'visible' => 1, 'default' => 'null', 'position' => 40, 'searchall' => 0, 'isameasure' => 1, 'help' => 'Help text'),
1226 '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'),
1227 'description' => array('type' => 'text', 'label' => 'Descrption', 'enabled' => 1, 'visible' => 0, 'position' => 60),
1228 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 61),
1229 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 62),
1230 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 500),
1231 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 501),
1232 //'date_valid' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 502),
1233 'fk_user_creat' => array('type' => 'integer', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 510),
1234 'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 511),
1235 //'fk_user_valid' => array('type' => 'integer', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 512),
1236 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'index' => 0, 'position' => 1000),
1237 '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')),
1238 );*/
1239
1240 $stringforproperties = '// BEGIN MODULEBUILDER PROPERTIES'."\n";
1241 $stringforproperties .= 'public $fields = array('."\n";
1242 $i = 10;
1243 while ($obj = $db->fetch_object($_results)) {
1244 // fieldname
1245 $fieldname = $obj->Field;
1246 // type
1247 $type = $obj->Type;
1248 if ($type == 'int(11)') {
1249 $type = 'integer';
1250 } elseif ($type == 'float') {
1251 $type = 'real';
1252 } elseif (strstr($type, 'tinyint')) {
1253 $type = 'integer';
1254 } elseif (strstr($type, 'url')) {
1255 $type = 'varchar(255)';
1256 } elseif ($obj->Field == 'fk_soc') {
1257 $type = 'integer:Societe:societe/class/societe.class.php';
1258 } elseif (preg_match('/^fk_proj/', $obj->Field)) {
1259 $type = 'integer:Project:projet/class/project.class.php:1:fk_statut=1';
1260 } elseif (preg_match('/^fk_prod/', $obj->Field)) {
1261 $type = 'integer:Product:product/class/product.class.php:1';
1262 } elseif ($obj->Field == 'fk_warehouse') {
1263 $type = 'integer:Entrepot:product/stock/class/entrepot.class.php';
1264 } elseif (preg_match('/^(fk_user|fk_commercial)/', $obj->Field)) {
1265 $type = 'integer:User:user/class/user.class.php';
1266 }
1267
1268 // notnull
1269 $notnull = ($obj->Null == 'YES' ? 0 : 1);
1270 if ($fieldname == 'fk_user_modif') {
1271 $notnull = -1;
1272 }
1273 // label
1274 $label = preg_replace('/_/', '', ucfirst($fieldname));
1275 if ($fieldname == 'rowid') {
1276 $label = 'TechnicalID';
1277 }
1278 if ($fieldname == 'import_key') {
1279 $label = 'ImportId';
1280 }
1281 if ($fieldname == 'fk_soc') {
1282 $label = 'ThirdParty';
1283 }
1284 if (in_array($fieldname, array('tms', 'date_modification'))) {
1285 $label = 'DateModification';
1286 }
1287 if (in_array($fieldname, array('datec', 'date_creation'))) {
1288 $label = 'DateCreation';
1289 }
1290 if ($fieldname == 'date_valid') {
1291 $label = 'DateValidation';
1292 }
1293 if ($fieldname == 'datev') {
1294 $label = 'DateValidation';
1295 }
1296 if ($fieldname == 'note_private') {
1297 $label = 'NotePublic';
1298 }
1299 if ($fieldname == 'note_public') {
1300 $label = 'NotePrivate';
1301 }
1302 if ($fieldname == 'fk_user_creat') {
1303 $label = 'UserAuthor';
1304 }
1305 if ($fieldname == 'fk_user_modif') {
1306 $label = 'UserModif';
1307 }
1308 if ($fieldname == 'fk_user_valid') {
1309 $label = 'UserValidation';
1310 }
1311 // visible
1312 $visible = -1;
1313 if (in_array($fieldname, array('ref', 'label'))) {
1314 $visible = 1;
1315 }
1316 if ($fieldname == 'entity') {
1317 $visible = -2;
1318 }
1319 if ($fieldname == 'entity') {
1320 $visible = -2;
1321 }
1322 if ($fieldname == 'import_key') {
1323 $visible = -2;
1324 }
1325 if ($fieldname == 'fk_user_creat') {
1326 $visible = -2;
1327 }
1328 if ($fieldname == 'fk_user_modif') {
1329 $visible = -2;
1330 }
1331 if (in_array($fieldname, array('ref_ext', 'model_pdf', 'note_public', 'note_private'))) {
1332 $visible = 0;
1333 }
1334 // enabled
1335 $enabled = 1;
1336 // default
1337 $default = '';
1338 if ($fieldname == 'entity') {
1339 $default = 1;
1340 }
1341 // position
1342 $position = $i;
1343 if (in_array($fieldname, array('status', 'statut', 'fk_status', 'fk_statut'))) {
1344 $position = 500;
1345 }
1346 if ($fieldname == 'import_key') {
1347 $position = 900;
1348 }
1349 // $alwayseditable
1350 $alwayseditable = 0;
1351 if ($fieldname == 'label') {
1352 $alwayseditable = 1;
1353 } else {
1354 $alwayseditable = 0;
1355 }
1356 // index
1357 $index = 0;
1358 if ($fieldname == 'entity') {
1359 $index = 1;
1360 }
1361 // css, cssview, csslist
1362 $css = '';
1363 $cssview = '';
1364 $csslist = '';
1365 if (preg_match('/^fk_/', $fieldname)) {
1366 $css = 'maxwidth500 widthcentpercentminusxx';
1367 }
1368 if ($fieldname == 'label') {
1369 $css = 'minwidth300';
1370 $cssview = 'wordbreak';
1371 }
1372 if (in_array($fieldname, array('note_public', 'note_private'))) {
1373 $cssview = 'wordbreak';
1374 }
1375 if (in_array($fieldname, array('ref', 'label')) || preg_match('/integer:/', $type)) {
1376 $csslist = 'tdoverflowmax150';
1377 }
1378
1379 // type
1380 $picto = '';
1381 if (isset($obj->Picto)) { // This should never exists
1382 $picto = $obj->Picto;
1383 }
1384 if (preg_match('/^fk_soc/', $obj->Field)) {
1385 $picto = 'company';
1386 } elseif (preg_match('/^fk_contact/', $obj->Field)) {
1387 $picto = 'contact';
1388 } elseif (preg_match('/^fk_bank/', $obj->Field)) {
1389 $picto = 'bank';
1390 } elseif (preg_match('/^fk_user/', $obj->Field)) {
1391 $picto = 'user';
1392 } elseif (preg_match('/^fk_warehouse/', $obj->Field)) {
1393 $picto = 'warehouse';
1394 } elseif (preg_match('/^fk_prod/', $obj->Field)) {
1395 $picto = 'product';
1396 } elseif (preg_match('/^fk_proj/', $obj->Field)) {
1397 $picto = 'project';
1398 } elseif (preg_match('/^fk_task/', $obj->Field)) {
1399 $picto = 'task';
1400 }
1401
1402 // lang
1403 $lang = $module.'@'.$module;
1404
1405 // Build the property string
1406 $stringforproperties .= "'".$obj->Field."' => array('type' => '".$type."', 'label' => '".$label."',";
1407 if ($default != '') {
1408 $stringforproperties .= " 'default' => ".$default.",";
1409 }
1410 $stringforproperties .= " 'enabled' => ".$enabled.",";
1411 $stringforproperties .= " 'visible' => ".$visible;
1412 if ($notnull) {
1413 $stringforproperties .= ", 'notnull' => ".$notnull;
1414 }
1415 if ($alwayseditable) {
1416 $stringforproperties .= ", 'alwayseditable' => 1";
1417 }
1418 if ($fieldname == 'ref' || $fieldname == 'code') {
1419 $stringforproperties .= ", 'showoncombobox' => 1";
1420 }
1421 $stringforproperties .= ", 'position' => ".$position;
1422 if ($index) {
1423 $stringforproperties .= ", 'index' => ".$index;
1424 }
1425 if ($picto) {
1426 $stringforproperties .= ", 'picto' => '".$picto."'";
1427 }
1428 if ($css) {
1429 $stringforproperties .= ", 'css' => '".$css."'";
1430 }
1431 if ($cssview) {
1432 $stringforproperties .= ", 'cssview' => '".$cssview."'";
1433 }
1434 if ($csslist) {
1435 $stringforproperties .= ", 'csslist' => '".$csslist."'";
1436 }
1437
1438 $stringforproperties .= ", 'lang' => '".$lang."'";
1439
1440 $stringforproperties .= "),\n";
1441 $i += 5;
1442 }
1443 $stringforproperties .= ');'."\n";
1444 $stringforproperties .= '// END MODULEBUILDER PROPERTIES'."\n";
1445 }
1446 }
1447
1448 $filetogenerate = array();
1449 if (!$error) {
1450 // Copy some files
1451 $filetogenerate = [];
1452 foreach ([
1453 'myobject_card.php',
1454 'myobject_note.php',
1455 'myobject_contact.php',
1456 'myobject_document.php',
1457 'myobject_agenda.php',
1458 'myobject_list.php',
1459 'admin/myobject_extrafields.php',
1460 'ajax/myobject.php',
1461 'lib/mymodule_myobject.lib.php',
1462 //'test/phpunit/MyObjectTest.php',
1463 'sql/llx_mymodule_myobject.sql',
1464 'sql/llx_mymodule_myobject.key.sql',
1465 'sql/llx_mymodule_myobject_extrafields.sql',
1466 'sql/llx_mymodule_myobject_extrafields.key.sql',
1467 //'scripts/mymodule.php',
1468 'class/myobject.class.php',
1469 'class/myobjectstats.class.php',
1470 //'class/api_mymodule.class.php',
1471 'stats/myobject_index.php',
1472 ] as $templateFile) {
1473 $filetogenerate[$templateFile] = $ncObj->applyToFilename($templateFile);
1474 }
1475
1476 // Exclude tab page files for tabs not selected by user
1477 foreach (getModuleBuilderObjectTabs() as $tabkey => $tabinfo) {
1478 if (!in_array($tabkey, $enabledtabs, true)) {
1479 unset($filetogenerate[$tabinfo['file']]);
1480 }
1481 }
1482
1483 if (GETPOST('includerefgeneration', 'aZ09')) {
1484 dol_mkdir($destdir.'/core/modules/'.strtolower($module));
1485
1486 foreach ([
1487 'core/modules/mymodule/mod_myobject_advanced.php',
1488 'core/modules/mymodule/mod_myobject_standard.php',
1489 'core/modules/mymodule/modules_myobject.php',
1490 ] as $templateFile) {
1491 $filetogenerate[$templateFile] = $ncObj->applyToFilename($templateFile);
1492 }
1493 }
1494 if (GETPOST('includedocgeneration', 'aZ09')) {
1495 dol_mkdir($destdir.'/core/modules/'.strtolower($module));
1496 dol_mkdir($destdir.'/core/modules/'.strtolower($module).'/doc');
1497
1498 foreach ([
1499 'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php',
1500 'core/modules/mymodule/doc/pdf_standard_myobject.modules.php',
1501 ] as $templateFile) {
1502 $filetogenerate[$templateFile] = $ncObj->applyToFilename($templateFile);
1503 }
1504 }
1505 $class = null;
1506 if (GETPOST('generatepermissions', 'aZ09')) {
1507 $firstobjectname = 'myobject';
1508 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1509 dol_include_once($pathtofile);
1510 $class = 'mod'.$module;
1511 $moduleobj = null;
1512 if (class_exists($class)) {
1513 try {
1514 $moduleobj = new $class($db);
1515 '@phan-var-force DolibarrModules $moduleobj';
1517 } catch (Exception $e) {
1518 $error++;
1519 dol_print_error($db, $e->getMessage());
1520 }
1521 }
1522 if (is_object($moduleobj)) {
1523 $rights = $moduleobj->rights;
1524 } else {
1525 $rights = [];
1526 }
1527 $moduledescriptorfile = $destdir.'/core/modules/mod'.$module.'.class.php';
1528 $checkComment = checkExistComment($moduledescriptorfile, 1);
1529 if ($checkComment < 0) {
1530 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
1531 } else {
1532 $generatePerms = reWriteAllPermissions($moduledescriptorfile, $rights, null, null, $objectname, $module, -2);
1533 if ($generatePerms < 0) {
1534 setEventMessages($langs->trans("WarningPermissionAlreadyExist", $langs->transnoentities($objectname)), null, 'warnings');
1535 }
1536 }
1537 }
1538
1539 if (!$error) {
1540 foreach ($filetogenerate as $srcfile => $destfile) {
1541 $result = dol_copy($srcdir.'/'.$srcfile, $destdir.'/'.$destfile, $newmask, 0);
1542 if ($result <= 0) {
1543 if ($result < 0) {
1544 $warning++;
1545 $langs->load("errors");
1546 setEventMessages($langs->trans("ErrorFailToCopyFile", $srcdir.'/'.$srcfile, $destdir.'/'.$destfile), null, 'errors');
1547 } else {
1548 // $result == 0
1549 setEventMessages($langs->trans("FileAlreadyExists", $destfile), null, 'warnings');
1550 }
1551 }
1552 $arrayreplacement = array(
1553 '/myobject\.class\.php/' => strtolower($objectname).'.class.php',
1554 '/myobject\.lib\.php/' => strtolower($objectname).'.lib.php',
1555 );
1556
1557 dolReplaceInFile($destdir.'/'.$destfile, $arrayreplacement, '', '0', 0, 1);
1558 }
1559 }
1560
1561 // Replace property section with $stringforproperties
1562 if (!$error && $stringforproperties) {
1563 //var_dump($stringforproperties);exit;
1564 $arrayreplacement = array(
1565 '/\/\/ BEGIN MODULEBUILDER PROPERTIES.*\/\/ END MODULEBUILDER PROPERTIES/ims' => $stringforproperties
1566 );
1567
1568 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1569 }
1570
1571 // Edit the class 'class/'.strtolower($objectname).'.class.php'
1572 if (GETPOST('includerefgeneration', 'aZ09')) {
1573 // Replace 'visible' => 1, 'noteditable' => 0, 'default' => ''
1574 $arrayreplacement = array(
1575 '/\'visible\'s*=>s*1,\s*\'noteditable\'s*=>s*0,\s*\'default\'s*=>s*\'\'/' => "'visible' => 4, 'noteditable' => 1, 'default' => '(PROV)'"
1576 );
1577 //var_dump($arrayreplacement);exit;
1578 //var_dump($destdir.'/class/'.strtolower($objectname).'.class.php');exit;
1579 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1580
1581 $arrayreplacement = array(
1582 '/\'models\' => 0,/' => '\'models\' => 1,'
1583 );
1584 dolReplaceInFile($destdir.'/core/modules/mod'.$module.'.class.php', $arrayreplacement, '', '0', 0, 1);
1585 }
1586
1587 // Edit the setup file and the card page
1588 if (GETPOST('includedocgeneration', 'aZ09')) {
1589 // Replace some var init into some files
1590 $arrayreplacement = array(
1591 '/\$includedocgeneration = 0;/' => '$includedocgeneration = 1;'
1592 );
1593 dolReplaceInFile($destdir.'/class/'.strtolower($objectname).'.class.php', $arrayreplacement, '', '0', 0, 1);
1594 dolReplaceInFile($destdir.'/'.strtolower($objectname).'_card.php', $arrayreplacement, '', '0', 0, 1);
1595
1596 $arrayreplacement = array(
1597 '/\'models\' => 0,/' => '\'models\' => 1,'
1598 );
1599
1600 dolReplaceInFile($destdir.'/core/modules/mod'.$module.'.class.php', $arrayreplacement, '', '0', 0, 1);
1601 }
1602
1603 // TODO Update entries '$myTmpObjects['MyObject'] = array('includerefgeneration' => 0, 'includedocgeneration' => 0);'
1604
1605
1606 // Scan for object class files
1607 $listofobject = dol_dir_list($destdir.'/class', 'files', 0, '\.class\.php$');
1608
1609 $firstobjectname = '';
1610 $stringtoadd = '';
1611 foreach ($listofobject as $fileobj) {
1612 if (preg_match('/^api_/', $fileobj['name'])) {
1613 continue;
1614 }
1615 if (preg_match('/^actions_/', $fileobj['name'])) {
1616 continue;
1617 }
1618
1619 $tmpcontent = file_get_contents($fileobj['fullname']);
1620 $reg = array();
1621 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
1622 $objectnameloop = $reg[1];
1623 if (empty($firstobjectname)) {
1624 $firstobjectname = $objectnameloop;
1625 }
1626 }
1627
1628 // Regenerate left menu entry in descriptor for $objectname
1629 $stringtoadd = "
1630 \$this->menu[\$r++] = array(
1631 'fk_menu' => 'fk_mainmenu=mymodule',
1632 'type' => 'left',
1633 'titre' => 'MyObject',
1634 'prefix' => img_picto('', \$this->picto, 'class=\"paddingright pictofixedwidth valignmiddle\"'),
1635 'mainmenu' => 'mymodule',
1636 'leftmenu' => 'myobject',
1637 'url' => '/mymodule/myobject_list.php',
1638 'langs' => 'mymodule@mymodule',
1639 'position' => 1000 + \$r,
1640 'enabled' => 'isModEnabled(\"mymodule\")',
1641 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "read")' : '1')."',
1642 'target' => '',
1643 'user' => 2,
1644 'object' => 'MyObject'
1645 );
1646 \$this->menu[\$r++] = array(
1647 'fk_menu' => 'fk_mainmenu=mymodule,fk_leftmenu=myobject',
1648 'type' => 'left',
1649 'titre' => 'List MyObject',
1650 'mainmenu' => 'mymodule',
1651 'leftmenu' => 'mymodule_myobject_list',
1652 'url' => '/mymodule/myobject_list.php',
1653 'langs' => 'mymodule@mymodule',
1654 'position' => 1000 + \$r,
1655 'enabled' => 'isModEnabled(\"mymodule\")',
1656 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "read")' : '1')."',
1657 'target' => '',
1658 'user' => 2,
1659 'object' => 'MyObject'
1660 );
1661 \$this->menu[\$r++] = array(
1662 'fk_menu' => 'fk_mainmenu=mymodule,fk_leftmenu=myobject',
1663 'type' => 'left',
1664 'titre' => 'New MyObject',
1665 'mainmenu' => 'mymodule',
1666 'leftmenu' => 'mymodule_myobject_new',
1667 'url' => '/mymodule/myobject_card.php?action=create',
1668 'langs' => 'mymodule@mymodule',
1669 'position' => 1000 + \$r,
1670 'enabled' => 'isModEnabled(\"mymodule\")',
1671 'perms' => '".(GETPOST('generatepermissions') ? '$user->hasRight("mymodule", "myobject", "write")' : '1')."',
1672 'target' => '',
1673 'user' => 2,
1674 'object' => 'MyObject'
1675 );";
1676 $stringtoadd = $ncObj->applyTo($stringtoadd);
1677
1678 $moduledescriptorfile = $destdir.'/core/modules/mod'.$module.'.class.php';
1679 }
1680 // TODO Allow a replace with regex using dolReplaceInFile with param arryreplacementisregex to 1
1681 // TODO Avoid duplicate addition
1682
1683 // load class and check if menu exist with same object name
1684 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1685 dol_include_once($pathtofile);
1686 $class = 'mod'.$module;
1687 $moduleobj = null;
1688 if (class_exists($class)) {
1689 try {
1690 $moduleobj = new $class($db);
1691 '@phan-var-force DolibarrModules $moduleobj';
1693 } catch (Exception $e) {
1694 $error++;
1695 dol_print_error($db, $e->getMessage());
1696 }
1697 }
1698 if (is_object($moduleobj)) {
1699 $menus = $moduleobj->menu;
1700 } else {
1701 $menus = array();
1702 }
1703 $counter = 0 ;
1704 foreach ($menus as $menu) {
1705 if ($menu['leftmenu'] == strtolower($objectname)) {
1706 $counter++;
1707 }
1708 }
1709 if (!$counter) {
1710 $checkComment = checkExistComment($moduledescriptorfile, 0);
1711 if ($checkComment < 0) {
1712 $warning++;
1713 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), basename($moduledescriptorfile)), null, 'warnings');
1714 } else {
1715 $arrayofreplacement = array(
1716 '/* 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 */'
1717 );
1718 dolReplaceInFile($moduledescriptorfile, $arrayofreplacement);
1719 }
1720 }
1721 // Add module descriptor to list of files to replace "MyObject' string with real name of object.
1722 $filetogenerate[] = 'core/modules/mod'.$module.'.class.php';
1723 }
1724
1725 if (! $error && GETPOST('nogeneratelines', 'aZ09')) {
1726 $checkComment = checkExistComment($moduledescriptorfile, 0);
1727 if ($checkComment < 0) {
1728 $warning++;
1729 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), basename($moduledescriptorfile)), null, 'warnings');
1730 } else {
1731 // File path
1732 $TFilePaths = [
1733 $destdir . '/class/' . strtolower($objectname) . '.class.php',
1734 $destdir . '/class/api_' . strtolower($module) . '.class.php',
1735 $destdir . '/' . strtolower($objectname) . '_card.php'
1736 ];
1737
1738 // Pattern to remove everything between the tags
1739 $pattern = '/\/\/BEGIN MODULEBUILDER LINES.*?\/\/END MODULEBUILDER LINES\s*/s';
1740 foreach ($TFilePaths as $filePath) {
1741 // Skip files that were not generated (e.g. the API class when API generation is disabled);
1742 // a missing optional file must not abort the whole object generation.
1743 if (file_exists($filePath) && !removePatternFromFile($filePath, $pattern)) {
1744 $error++;
1745 }
1746 }
1747 }
1748 }
1749
1750 // Apply object tab selection on the generated lib file:
1751 // selected tabs -> hardcode the show flag to 1 (visible without extra config) ; unselected -> remove flag declaration and tab block
1752 if (!$error) {
1753 $libdestfile = $destdir.'/'.$ncObj->applyToFilename('lib/mymodule_myobject.lib.php');
1754 foreach (getModuleBuilderObjectTabs() as $tabkey => $tabinfo) {
1755 $marker = $tabinfo['marker'];
1756 if (in_array($tabkey, $enabledtabs, true)) {
1757 $arrayreplacement = array(
1758 '/\$'.$tabinfo['var'].' = getDolGlobalInt\‍([^;]*\‍);/' => '$'.$tabinfo['var'].' = 1;'
1759 );
1760 if (dolReplaceInFile($libdestfile, $arrayreplacement, '', '0', 0, 1) < 0) {
1761 $error++;
1762 dol_syslog("modulebuilder: failed to activate tab flag '".$tabkey."' in ".$libdestfile, LOG_ERR);
1763 }
1764 } else {
1765 if (!removePatternFromFile($libdestfile, '/\h*\/\/ BEGIN MODULEBUILDER TABFLAG '.$marker.'.*?\/\/ END MODULEBUILDER TABFLAG '.$marker.'\s*/s')
1766 || !removePatternFromFile($libdestfile, '/\h*\/\/ BEGIN MODULEBUILDER TAB '.$marker.'.*?\/\/ END MODULEBUILDER TAB '.$marker.'\s*/s')) {
1767 $error++;
1768 dol_syslog("modulebuilder: failed to purge tab '".$tabkey."' in ".$libdestfile, LOG_ERR);
1769 }
1770 }
1771 }
1772 // Agenda has an extra event widget on the card page: purge it too to avoid a dead link when the agenda tab is excluded
1773 if (!$error && !in_array('agenda', $enabledtabs, true)) {
1774 $carddestfile = $destdir.'/'.$ncObj->applyToFilename('myobject_card.php');
1775 if (!removePatternFromFile($carddestfile, '/\h*\/\/ BEGIN MODULEBUILDER TAB AGENDA.*?\/\/ END MODULEBUILDER TAB AGENDA\s*/s')) {
1776 $error++;
1777 dol_syslog("modulebuilder: failed to purge agenda widget in ".$carddestfile, LOG_ERR);
1778 }
1779 }
1780 if ($objectalreadyexists) {
1781 setEventMessages($langs->trans("WarningTabSelectionOnRegeneration"), null, 'warnings');
1782 }
1783 }
1784
1785 if (!$error) {
1786 // Edit PHP files to make replacement
1787 foreach ($filetogenerate as $destfile) {
1788 $phpfileval['fullname'] = $destdir.'/'.$destfile;
1789
1790 //var_dump($phpfileval['fullname']);
1791 $licenceValue = getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')
1792 ? dol_print_date($now, '%Y') . ' ' . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')
1793 : getLicenceHeader($user, $langs, $now);
1794
1795 $arrayreplacement = array_merge(
1796 $ncObj->getSubstitutionMap(),
1797 [
1798 'htdocs/modulebuilder/template/' => $ncObj->moduleNameLower,
1799 '---Replace with your own copyright and developer email---' => $licenceValue,
1800 ]
1801 );
1802
1803 if (basename($phpfileval['fullname']) === 'mod'.$module.'.class.php') {
1804 // Module descriptor: substitute content but keep the persistent MODULEBUILDER markers intact
1805 $result = dolReplaceInFilePreservingModuleBuilderMarkers($phpfileval['fullname'], $arrayreplacement);
1806 } else {
1807 $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); // @phpstan-ignore-line
1808 }
1809 //var_dump($result);
1810 if ($result < 0) {
1811 setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
1812 } else {
1813 modulebuilderValidateGeneratedFile($phpfileval['fullname'], $ncObj);
1814 }
1815 }
1816 }
1817
1818 if (!$error && $ncObj !== null) {
1819 // Apply object name substitution to ALL PHP files in the module directory.
1820 // initmodule only substitutes the module name; files it creates (e.g. testmodindex.php,
1821 // lib/testmod.lib.php, admin/setup.php) still contain myobject/mymodule placeholders
1822 // that must be resolved when an object is first added.
1823 $licenceValueAll = getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')
1824 ? dol_print_date($now, '%Y') . ' ' . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR')
1825 : getLicenceHeader($user, $langs, $now);
1826 $moduleReplacementAll = array_merge(
1827 $ncObj->getSubstitutionMap(),
1828 [
1829 'htdocs/modulebuilder/template/' => $ncObj->moduleNameLower,
1830 '---Replace with your own copyright and developer email---' => $licenceValueAll,
1831 ]
1832 );
1833 $allModulePhpFiles = dol_dir_list($destdir, 'files', 1, '\.php$');
1834 // The module descriptor must NOT go through the blanket substitution: it keeps persistent
1835 // MYOBJECT/MYMODULE markers (TOPMENU/LEFTMENU) reused when generating subsequent objects, and its
1836 // own placeholders are already resolved by initmodule and the dedicated menu/permission blocks.
1837 $moduledescriptorbasename = 'mod'.$module.'.class.php';
1838 if (is_array($allModulePhpFiles) && !empty($allModulePhpFiles)) {
1839 foreach ($allModulePhpFiles as $phpFileval) {
1840 if (basename($phpFileval['fullname']) === $moduledescriptorbasename) {
1841 continue;
1842 }
1843 $result = dolReplaceInFile($phpFileval['fullname'], $moduleReplacementAll);
1844 if ($result < 0) {
1845 setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpFileval['fullname']), null, 'warnings');
1846 }
1847 }
1848 }
1849 // Delete initmodule placeholder files superseded by initobject-generated files.
1850 $moduleLowerForPlaceholder = strtolower($module);
1851 foreach ([
1852 $destdir . '/stats/myobject_index.php',
1853 $destdir . '/lib/' . $moduleLowerForPlaceholder . '_myobject.lib.php',
1854 ] as $placeholder) {
1855 if (file_exists($placeholder)) {
1856 dol_delete_file($placeholder);
1857 }
1858 }
1859 }
1860
1861 $object = null;
1862 if (!$error) {
1863 // Edit the class file to write properties
1864 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask);
1865
1866 if (is_numeric($object) && $object <= 0) {
1867 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1868 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1869 $warning++;
1870 }
1871 // check if documentation was generate and add table of properties object
1872 $file = $destdir.'/class/'.strtolower($objectname).'.class.php';
1873 $destfile = $destdir.'/doc/Documentation.asciidoc';
1874
1875 if (file_exists($destfile)) {
1876 writePropsInAsciiDoc($file, $objectname, $destfile);
1877 }
1878 }
1879 if (!$error && $object !== null) {
1880 // Edit sql with new properties
1881 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, '', $object);
1882
1883 if ($result <= 0) {
1884 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null);
1885 $error++;
1886 }
1887 }
1888
1889 if (!$error) {
1890 setEventMessages($langs->trans('FilesForObjectInitialized', $objectname), null);
1891 $tabobj = $objectname;
1892 } else {
1893 $tabobj = 'newobject';
1894 }
1895
1896 // check if module is enabled
1897 if (isModEnabled(strtolower($module))) {
1898 $result = unActivateModule(strtolower($module));
1899 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
1900 if ($result) {
1901 setEventMessages($result, null, 'errors');
1902 }
1903 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
1904 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module);
1905 exit;
1906 }
1907}
1908
1909// Add a dictionary
1910if ($dirins && $action == 'initdic' && $module && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
1911 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1912 $destdir = $dirins.'/'.strtolower($module);
1913 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1914
1915 if (!GETPOST('dicname')) {
1916 $error++;
1917 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Table")), null, 'errors');
1918 }
1919 if (!GETPOST('label')) {
1920 $error++;
1921 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
1922 }
1923 if (!$error) {
1924 $newdicname = $dicname;
1925 if (!preg_match('/^c_/', $newdicname)) {
1926 $newdicname = 'c_'.$dicname;
1927 }
1928 dol_include_once($pathtofile);
1929 $class = 'mod'.$module;
1930
1931 $moduleobj = null;
1932 if (class_exists($class)) {
1933 try {
1934 $moduleobj = new $class($db);
1935 '@phan-var-force DolibarrModules $moduleobj';
1937 } catch (Exception $e) {
1938 $error++;
1939 dol_print_error($db, $e->getMessage());
1940 }
1941 } else {
1942 $error++;
1943 }
1944 if ($moduleobj === null) {
1945 $langs->load("errors");
1946 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1947 exit;
1948 }
1949 $dictionaries = $moduleobj->dictionaries;
1950 $checkComment = checkExistComment($moduledescriptorfile, 2);
1951 if ($checkComment < 0) {
1952 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
1953 } else {
1954 createNewDictionnary($module, $moduledescriptorfile, $newdicname, $dictionaries);
1955 if (function_exists('opcache_invalidate')) {
1956 opcache_reset(); // remove the include cache hell !
1957 }
1958 clearstatcache(true);
1959 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
1960 exit;
1961 }
1962 }
1963}
1964
1965// Delete a SQL table
1966if ($dirins && ($action == 'droptable' || $action == 'droptableextrafields') && !empty($module) && !empty($tabobj) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
1967 $objectname = $tabobj;
1968
1969 $arrayoftables = array();
1970 if ($action == 'droptable') { // Test on permission already done
1971 $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj);
1972 }
1973 if ($action == 'droptableextrafields') { // Test on permission already done
1974 $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj).'_extrafields';
1975 }
1976
1977 foreach ($arrayoftables as $tabletodrop) {
1978 $nb = -1;
1979 $sql = "SELECT COUNT(*) as nb FROM ".$tabletodrop;
1980 $resql = $db->query($sql);
1981 if ($resql) {
1982 $obj = $db->fetch_object($resql);
1983 if ($obj) {
1984 $nb = (int) $obj->nb;
1985 }
1986 } else {
1987 if ($db->lasterrno() == 'DB_ERROR_NOSUCHTABLE') {
1988 setEventMessages($langs->trans("TableDoesNotExists", $tabletodrop), null, 'warnings');
1989 } else {
1991 }
1992 }
1993 if ($nb == 0) {
1994 $resql = $db->DDLDropTable($tabletodrop);
1995 //var_dump($resql);
1996 setEventMessages($langs->trans("TableDropped", $tabletodrop), null, 'mesgs');
1997 } elseif ($nb > 0) {
1998 setEventMessages($langs->trans("TableNotEmptyDropCanceled", $tabletodrop), null, 'warnings');
1999 }
2000 }
2001}
2002
2003if ($dirins && $action == 'addproperty' && empty($cancel) && !empty($module) && (!empty($tabobj) || !empty(GETPOST('obj'))) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2004 $error = 0;
2005
2006 $objectname = (GETPOST('obj') ? GETPOST('obj') : $tabobj);
2007
2008 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2009 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
2010
2011 $srcdir = $dirread.'/'.strtolower($module);
2012 $destdir = $dirins.'/'.strtolower($module);
2013 dol_mkdir($destdir);
2014
2015 $objects = dolGetListOfObjectClasses($destdir);
2016 if (!in_array($objectname, array_values($objects))) {
2017 $error++;
2018 setEventMessages($langs->trans("ErrorObjectNotFound", $langs->transnoentities($objectname)), null, 'errors');
2019 }
2020
2021 $addfieldentry = array();
2022
2023 // We click on add property
2024 if (!GETPOST('regenerateclasssql') && !GETPOST('regeneratemissing')) {
2025 if (!GETPOST('propname', 'aZ09')) {
2026 $error++;
2027 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Name")), null, 'errors');
2028 }
2029 if (!GETPOST('proplabel', 'alpha')) {
2030 $error++;
2031 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2032 }
2033 if (!GETPOST('proptype', 'alpha')) {
2034 $error++;
2035 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
2036 }
2037
2038
2039 if (!$error && !GETPOST('regenerateclasssql') && !GETPOST('regeneratemissing')) {
2040 // Preserve case for composite types such as 'integer:Societe:societe/class/societe.class.php:1:(...__SHARED_ENTITIES__...)'
2041 // because the colon-separated parts include PHP class names (case-sensitive) and __XXX__ substitution
2042 // tokens that are uppercase by convention. Only lowercase simple atomic types (#34602).
2043 $proptype = GETPOST('proptype', 'alpha');
2044 if (strpos($proptype, ':') === false && strpos($proptype, '_') === false) {
2045 $proptype = strtolower($proptype);
2046 }
2047 $addfieldentry = array(
2048 'name' => GETPOST('propname', 'aZ09'),
2049 'label' => GETPOST('proplabel', 'alpha'),
2050 'type' => $proptype,
2051 'arrayofkeyval' => GETPOST('proparrayofkeyval', 'nohtml'), // Example json string '{"0":"Draft","1":"Active","-1":"Cancel"}'
2052 'visible' => GETPOST('propvisible', 'alphanohtml'),
2053 'enabled' => GETPOST('propenabled', 'alphanohtml'),
2054 'position' => GETPOSTINT('propposition'),
2055 'notnull' => GETPOSTINT('propnotnull'),
2056 'index' => GETPOSTINT('propindex'),
2057 'foreignkey' => GETPOST('propforeignkey', 'alpha'),
2058 'searchall' => GETPOSTINT('propsearchall'),
2059 'isameasure' => GETPOSTINT('propisameasure'),
2060 'showoncombobox' => GETPOSTINT('propshowoncombobox'),
2061 'comment' => GETPOST('propcomment', 'alpha'),
2062 'help' => GETPOST('prophelp', 'alpha'),
2063 'css' => GETPOST('propcss', 'alpha'), // Can be 'maxwidth500 widthcentpercentminusxx' for example
2064 'cssview' => GETPOST('propcssview', 'alpha'),
2065 'csslist' => GETPOST('propcsslist', 'alpha'),
2066 'default' => GETPOST('propdefault', 'restricthtml'),
2067 'noteditable' => GETPOSTINT('propnoteditable'),
2068 //'alwayseditable' => GETPOSTINT('propalwayseditable'),
2069 'validate' => GETPOSTINT('propvalidate')
2070 );
2071
2072 if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
2073 $tmpdecode = json_decode($addfieldentry['arrayofkeyval'], true);
2074 if ($tmpdecode) { // If string is already a json
2075 $addfieldentry['arrayofkeyval'] = $tmpdecode;
2076 } else { // If string is a list of lines with "key,value"
2077 $tmparray = dolExplodeIntoArray($addfieldentry['arrayofkeyval'], "\n", ",");
2078 $addfieldentry['arrayofkeyval'] = $tmparray;
2079 }
2080 }
2081 }
2082 }
2083
2084 /*if (GETPOST('regeneratemissing'))
2085 {
2086 setEventMessages($langs->trans("FeatureNotYetAvailable"), null, 'warnings');
2087 $error++;
2088 }*/
2089
2090 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
2091
2092 $object = null;
2093 // Edit the class file to write properties
2094 if (!$error) {
2095 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, $addfieldentry, $moduletype);
2096
2097 if (is_numeric($object) && $object <= 0) {
2098 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
2099 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
2100 $error++;
2101 }
2102 }
2103
2104 // Edit sql with new properties
2105 if (!$error && $object !== null) {
2106 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object, $moduletype);
2107
2108 if ($result <= 0) {
2109 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
2110 $error++;
2111 }
2112 }
2113
2114 if (!$error) {
2115 clearstatcache(true);
2116
2117 setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
2118
2119 setEventMessages($langs->trans('WarningDatabaseIsNotUpdated'), null);
2120
2121 // Make a redirect to reload all data
2122 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname.'&nocache='.time());
2123 exit;
2124 }
2125}
2126
2127if ($dirins && $action == 'confirm_deleteproperty' && $propertykey /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2128 $objectname = $tabobj;
2129
2130 $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2131 $moduletype = $listofmodules[strtolower($module)]['moduletype'];
2132
2133 $srcdir = $dirread.'/'.strtolower($module);
2134 $destdir = $dirins.'/'.strtolower($module);
2135 dol_mkdir($destdir);
2136
2137 $object = null;
2138 // Edit the class file to write properties
2139 if (!$error) {
2140 $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, array(), $propertykey);
2141
2142 if (is_numeric($object) && $object <= 0) {
2143 $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
2144 setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
2145 $error++;
2146 }
2147 }
2148
2149 // Edit sql with new properties
2150 if (!$error && $object !== null) {
2151 $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object);
2152
2153 if ($result <= 0) {
2154 setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
2155 $error++;
2156 }
2157 }
2158
2159 if (!$error) {
2160 setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
2161
2162 clearstatcache(true);
2163
2164 // Make a redirect to reload all data
2165 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname);
2166 exit;
2167 }
2168}
2169
2170if ($dirins && $action == 'confirm_deletemodule' /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2171 if (preg_match('/[^a-z0-9_]/i', $module)) {
2172 $error++;
2173 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2174 }
2175
2176 if (!$error) {
2177 $modulelowercase = strtolower($module);
2178
2179 // Dir for module
2180 $dir = $dirins.'/'.$modulelowercase;
2181
2182 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2183
2184 // Dir for module
2185 $dir = dol_buildpath($modulelowercase, 0);
2186
2187 // Zip file to build
2188 $FILENAMEZIP = '';
2189
2190 // Load module
2191 dol_include_once($pathtofile);
2192 $class = 'mod'.$module;
2193
2194 $moduleobj = null;
2195
2196 if (class_exists($class)) {
2197 try {
2198 $moduleobj = new $class($db);
2199 '@phan-var-force DolibarrModules $moduleobj';
2201 } catch (Exception $e) {
2202 $error++;
2203 dol_print_error($db, $e->getMessage());
2204 }
2205 } else {
2206 $error++;
2207 $langs->load("errors");
2208 setEventMessages($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module), null, 'warnings');
2209 }
2210
2211 if ($moduleobj) {
2212 $moduleobj->remove();
2213 }
2214
2215 $result = dol_delete_dir_recursive($dir);
2216
2217 if ($result > 0) {
2218 setEventMessages($langs->trans("DirWasRemoved", $modulelowercase), null);
2219
2220 clearstatcache(true);
2221 if (function_exists('opcache_invalidate')) {
2222 opcache_reset(); // remove the include cache hell !
2223 }
2224
2225 header("Location: ".$_SERVER["PHP_SELF"].'?module=deletemodule');
2226 exit;
2227 } else {
2228 setEventMessages($langs->trans("PurgeNothingToDelete"), null, 'warnings');
2229 }
2230 }
2231
2232 $action = '';
2233 $module = 'deletemodule';
2234}
2235
2236if ($dirins && $action == 'confirm_deleteobject' && $objectname /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2237 if (preg_match('/[^a-z0-9_]/i', $objectname)) {
2238 $error++;
2239 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2240 }
2241
2242 if (!$error) {
2243 $modulelowercase = strtolower($module);
2244 $objectlowercase = strtolower($objectname);
2245
2246 // Dir for module
2247 $dir = $dirins.'/'.$modulelowercase;
2248
2249 // Delete some files
2250 try {
2251 $ncObjDel = new NamingContract($module, $objectname);
2252 } catch (\InvalidArgumentException $e) {
2253 $error++;
2254 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2255 $ncObjDel = null;
2256 }
2257 $filetodelete = [];
2258 if (!$error && $ncObjDel !== null) {
2259 foreach ([
2260 'myobject_card.php',
2261 'myobject_note.php',
2262 'myobject_contact.php',
2263 'myobject_document.php',
2264 'myobject_agenda.php',
2265 'myobject_list.php',
2266 'admin/myobject_extrafields.php',
2267 'lib/mymodule_myobject.lib.php',
2268 'sql/llx_mymodule_myobject.sql',
2269 'sql/llx_mymodule_myobject_extrafields.sql',
2270 'sql/llx_mymodule_myobject.key.sql',
2271 'sql/llx_mymodule_myobject_extrafields.key.sql',
2272 'scripts/myobject.php',
2273 'class/myobject.class.php',
2274 'class/myobjectstats.class.php',
2275 'core/modules/mymodule/mod_myobject_advanced.php',
2276 'core/modules/mymodule/mod_myobject_standard.php',
2277 'core/modules/mymodule/modules_myobject.php',
2278 'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php',
2279 'core/modules/mymodule/doc/pdf_standard_myobject.modules.php',
2280 'stats/myobject_index.php',
2281 ] as $templateFile) {
2282 $filetodelete[$templateFile] = $ncObjDel->applyToFilename($templateFile);
2283 }
2284 // Exceptions: target filenames differ from simple token substitution
2285 $filetodelete['ajax/myobject.lib.php'] = 'ajax/' . $ncObjDel->objectNameLower . '.php';
2286 $filetodelete['test/phpunit/MyObjectTest.php'] = 'test/phpunit/' . $ncObjDel->objectNameLower . 'Test.php';
2287 $filetodelete['class/api_myobject.class.php'] = 'class/api_' . $ncObjDel->moduleNameLower . '.class.php';
2288 }
2289
2290 //menu for the object selected
2291 // load class and check if menu,permission,documentation exist for this object
2292 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2293 dol_include_once($pathtofile);
2294 $class = 'mod'.$module;
2295 $moduleobj = null;
2296 if (class_exists($class)) {
2297 try {
2298 $moduleobj = new $class($db);
2299 '@phan-var-force DolibarrModules $moduleobj';
2301 } catch (Exception $e) {
2302 $error++;
2303 dol_print_error($db, $e->getMessage());
2304 }
2305 } else {
2306 $error++;
2307 $langs->load("errors");
2308 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2309 exit;
2310 }
2311 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2312
2313 // delete menus linked to the object
2314 $menus = $moduleobj->menu;
2315 $rewriteMenu = checkExistComment($moduledescriptorfile, 0);
2316
2317 if ($rewriteMenu < 0) {
2318 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
2319 } else {
2320 reWriteAllMenus($moduledescriptorfile, $menus, $objectname, null, -1);
2321 }
2322
2323 // regenerate permissions and delete them
2324 $permissions = $moduleobj->rights;
2325 $rewritePerms = checkExistComment($moduledescriptorfile, 1);
2326 if ($rewritePerms < 0) {
2327 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2328 } else {
2329 reWriteAllPermissions($moduledescriptorfile, $permissions, null, null, $objectname, '', -1);
2330 }
2331 if ($rewritePerms && $rewriteMenu) {
2332 // check if documentation has been generated
2333 $file_doc = $dirins.'/'.strtolower($module).'/doc/Documentation.asciidoc';
2334 deletePropsAndPermsFromDoc($file_doc, $objectname);
2335
2336 clearstatcache(true);
2337 if (function_exists('opcache_invalidate')) {
2338 opcache_reset(); // remove the include cache hell !
2339 }
2340 $resultko = 0;
2341 foreach ($filetodelete as $tmpfiletodelete) {
2342 $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete, 0, 0, 1);
2343 $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete.'.back', 0, 0, 1);
2344 if (!$resulttmp) {
2345 $resultko++;
2346 }
2347 }
2348
2349 if ($resultko == 0) {
2350 setEventMessages($langs->trans("FilesDeleted"), null);
2351 } else {
2352 setEventMessages($langs->trans("ErrorSomeFilesCouldNotBeDeleted"), null, 'warnings');
2353 }
2354 }
2355 }
2356
2357 $action = '';
2358 if (! $error) {
2359 $tabobj = 'newobject';
2360 } else {
2361 $tabobj = 'deleteobject';
2362 }
2363
2364 // check if module is enabled
2365 if (isModEnabled(strtolower($module))) {
2366 $result = unActivateModule(strtolower($module));
2367 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2368 if ($result) {
2369 setEventMessages($result, null, 'errors');
2370 }
2371 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2372 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&tabobj=deleteobject&module='.urlencode($module));
2373 exit;
2374 }
2375}
2376
2377if (($dirins && $action == 'confirm_deletedictionary' && $dicname) || ($dirins && $action == 'confirm_deletedictionary' && GETPOST('dictionnarykey')) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2378 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2379 $destdir = $dirins.'/'.strtolower($module);
2380 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2381
2382 if (preg_match('/[^a-z0-9_]/i', $dicname)) {
2383 $error++;
2384 setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
2385 }
2386
2387 if (!empty($dicname)) {
2388 $newdicname = $dicname;
2389 if (!preg_match('/^c_/', $newdicname)) {
2390 $newdicname = 'c_'.strtolower($dicname);
2391 }
2392 } else {
2393 $newdicname = null;
2394 }
2395
2396 dol_include_once($pathtofile);
2397 $class = 'mod'.$module;
2398
2399 $moduleobj = null;
2400 if (class_exists($class)) {
2401 try {
2402 $moduleobj = new $class($db);
2403 '@phan-var-force DolibarrModules $moduleobj';
2405 } catch (Exception $e) {
2406 $error++;
2407 dol_print_error($db, $e->getMessage());
2408 }
2409 } else {
2410 $error++;
2411 }
2412 if ($moduleobj === null) {
2413 $langs->load("errors");
2414 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2415 exit;
2416 }
2417
2418 $dicts = $moduleobj->dictionaries;
2419 $checkComment = checkExistComment($moduledescriptorfile, 2);
2420 if ($checkComment < 0) {
2421 $error++;
2422 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
2423 }
2424
2425 if (!empty(GETPOST('dictionnarykey'))) {
2426 $newdicname = $dicts['tabname'][GETPOSTINT('dictionnarykey') - 1];
2427 }
2428
2429 // Lookup the table dicname
2430 $checkTable = false;
2431 if ($newdicname !== null) {
2432 $checkTable = $db->DDLDescTable(MAIN_DB_PREFIX.strtolower($newdicname));
2433 }
2434
2435 if (is_bool($checkTable) || $db->num_rows($checkTable) <= 0) { // @phpstan-ignore-line
2436 $error++;
2437 }
2438
2439 // search the key by name
2440 $keyToDelete = null;
2441 foreach ($dicts['tabname'] as $key => $table) {
2442 //var_dump($table." /////// ".$newdicname);exit;
2443 if (strtolower($table) === $newdicname) {
2444 $keyToDelete = $key;
2445 break;
2446 }
2447 }
2448 // delete all dicname's key values from the dictionary
2449 if ($keyToDelete !== null) {
2450 $keysToDelete = ['tabname', 'tablib', 'tabsql', 'tabsqlsort', 'tabfield', 'tabfieldvalue', 'tabfieldinsert', 'tabrowid', 'tabcond', 'tabhelp'];
2451 foreach ($keysToDelete as $key) {
2452 unset($dicts[$key][$keyToDelete]);
2453 }
2454 } else {
2455 $error++;
2456 setEventMessages($langs->trans("ErrorDictionaryNotFound", ucfirst($dicname)), null, 'errors');
2457 }
2458 if (!$error && $newdicname !== null) {
2459 // delete table
2460 $_results = $db->DDLDropTable(MAIN_DB_PREFIX.strtolower($newdicname));
2461 if ($_results < 0) {
2463 $langs->load("errors");
2464 setEventMessages($langs->trans("ErrorTableNotFound", $newdicname), null, 'errors');
2465 }
2466 // rebuild file after update dictionaries
2467 $result = updateDictionaryInFile($module, $moduledescriptorfile, $dicts);
2468 if ($result > 0) {
2469 setEventMessages($langs->trans("DictionaryDeleted", ucfirst(substr($newdicname, 2))), null);
2470 }
2471 if (function_exists('opcache_invalidate')) {
2472 opcache_reset(); // remove the include cache hell !
2473 }
2474 clearstatcache(true);
2475 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
2476 exit;
2477 }
2478}
2479if ($dirins && $action == 'updatedictionary' && GETPOST('dictionnarykey') /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2480 $keydict = GETPOSTINT('dictionnarykey') - 1 ;
2481
2482 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2483 $destdir = $dirins.'/'.strtolower($module);
2484 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2485 dol_include_once($pathtofile);
2486 $class = 'mod'.$module;
2487
2488 $moduleobj = null;
2489 if (class_exists($class)) {
2490 try {
2491 $moduleobj = new $class($db);
2492 '@phan-var-force DolibarrModules $moduleobj';
2494 } catch (Exception $e) {
2495 $error++;
2496 dol_print_error($db, $e->getMessage());
2497 }
2498 } else {
2499 $error++;
2500 }
2501 if ($moduleobj === null) {
2502 $langs->load("errors");
2503 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2504 exit;
2505 }
2506
2507 $dicts = $moduleobj->dictionaries;
2508 if (!empty(GETPOST('tablib')) && GETPOST('tablib') !== $dicts['tablib'][$keydict]) {
2509 $dicts['tablib'][$keydict] = ucfirst(strtolower(GETPOST('tablib')));
2510 $checkComment = checkExistComment($moduledescriptorfile, 2);
2511 if ($checkComment < 0) {
2512 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Dictionaries"), "mod".$module."class.php"), null, 'warnings');
2513 } else {
2514 $updateDict = updateDictionaryInFile($module, $moduledescriptorfile, $dicts);
2515 if ($updateDict > 0) {
2516 setEventMessages($langs->trans("DictionaryNameUpdated", ucfirst(GETPOST('tablib'))), null);
2517 }
2518 if (function_exists('opcache_invalidate')) {
2519 opcache_reset(); // remove the include cache hell !
2520 }
2521 clearstatcache(true);
2522 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : ''));
2523 exit;
2524 }
2525 }
2526 //var_dump(GETPOST('tablib'));exit;
2527}
2528if ($dirins && $action == 'generatedoc' /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2529 $modulelowercase = strtolower($module);
2530
2531 // Dir for module
2532 $dirofmodule = dol_buildpath($modulelowercase, 0).'/doc';
2533
2534 $FILENAMEDOC = strtolower($module).'.html';
2535
2536 $util = new Utils($db);
2537 $result = $util->generateDoc($module);
2538
2539 if ($result > 0) {
2540 setEventMessages($langs->trans("DocFileGeneratedInto", $dirofmodule), null);
2541 } else {
2542 setEventMessages($util->error, $util->errors, 'errors');
2543 }
2544}
2545
2546if ($dirins && $action == 'generatepackage' /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2547 $modulelowercase = strtolower($module);
2548
2549 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2550
2551 // Dir for module
2552 $dir = dol_buildpath($modulelowercase, 0);
2553
2554 // Zip file to build
2555 $FILENAMEZIP = '';
2556
2557 // Load module
2558 dol_include_once($pathtofile);
2559 $class = 'mod'.$module;
2560
2561 $moduleobj = null;
2562 if (class_exists($class)) {
2563 try {
2564 $moduleobj = new $class($db);
2565 '@phan-var-force DolibarrModules $moduleobj';
2567 } catch (Exception $e) {
2568 $error++;
2569 dol_print_error($db, $e->getMessage());
2570 }
2571 } else {
2572 $error++;
2573 }
2574 if ($moduleobj === null) {
2575 $langs->load("errors");
2576 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
2577 exit;
2578 }
2579
2580 $arrayversion = explode('.', $moduleobj->version, 3);
2581 if (count($arrayversion)) {
2582 $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : '.'.$arrayversion[2]).'.zip';
2583
2584 $dirofmodule = dol_buildpath($modulelowercase, 0).'/bin';
2585 $outputfilezip = $dirofmodule.'/'.$FILENAMEZIP;
2586
2587 if (!dol_is_dir($dirofmodule)) {
2588 dol_mkdir($dirofmodule);
2589 }
2590 // Note: We exclude /bin/ to not include the already generated zip
2591 $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase);
2592
2593 if ($result > 0) {
2594 setEventMessages($langs->trans("ZipFileGeneratedInto", $outputfilezip), null);
2595 } else {
2596 $error++;
2597 $langs->load("errors");
2598 setEventMessages($langs->trans("ErrorFailToGenerateFile", $outputfilezip), null, 'errors');
2599 }
2600 } else {
2601 $error++;
2602 $langs->load("errors");
2603 setEventMessages($langs->trans("ErrorCheckVersionIsDefined"), null, 'errors');
2604 }
2605}
2606
2607// Add permission
2608if ($dirins && $action == 'addright' && !empty($module) && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2609 $error = 0;
2610
2611 // load class and check if right exist
2612 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2613 dol_include_once($pathtofile);
2614 $class = 'mod'.$module;
2615 $moduleobj = null;
2616 if (class_exists($class)) {
2617 try {
2618 $moduleobj = new $class($db);
2619 '@phan-var-force DolibarrModules $moduleobj';
2621 } catch (Exception $e) {
2622 $error++;
2623 dol_print_error($db, $e->getMessage());
2624 }
2625 }
2626
2627 // verify information entered
2628 if (!GETPOST('label', 'alpha')) {
2629 $error++;
2630 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2631 }
2632 if (!GETPOST('permissionObj', 'alpha')) {
2633 $error++;
2634 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2635 }
2636
2637 $id = GETPOST('id', 'alpha');
2638 $label = GETPOST('label', 'alpha');
2639 $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2640 $crud = GETPOST('crud', 'alpha');
2641
2642 //check existing object permission
2643 $counter = 0;
2644 $permsForObject = array();
2645 if (is_object($moduleobj)) {
2646 $permissions = $moduleobj->rights;
2647 } else {
2648 $permissions = array();
2649 }
2650 $allObject = array();
2651
2652 $countPerms = count($permissions);
2653
2654 for ($i = 0; $i < $countPerms; $i++) {
2655 if ($permissions[$i][4] == $objectForPerms) {
2656 $counter++;
2657 if (count($permsForObject) < 3) {
2658 $permsForObject[] = $permissions[$i];
2659 }
2660 }
2661 $allObject[] = $permissions[$i][4];
2662 }
2663
2664 // check if label of object already exists
2665 $countPermsObj = count($permsForObject);
2666 for ($j = 0; $j < $countPermsObj; $j++) {
2667 if (in_array($crud, $permsForObject[$j])) {
2668 $error++;
2669 setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($crud), $langs->transnoentities($objectForPerms)), null, 'errors');
2670 }
2671 }
2672
2673 $rightToAdd = array();
2674 if (!$error) {
2675 $key = $countPerms + 1;
2676 //prepare right to add
2677 $rightToAdd = array(
2678 0 => $id,
2679 1 => $label,
2680 4 => $objectForPerms,
2681 5 => $crud
2682 );
2683
2684 if (isModEnabled(strtolower($module))) {
2685 $result = unActivateModule(strtolower($module));
2686 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2687 if ($result) {
2688 setEventMessages($result, null, 'errors');
2689 }
2690 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2691 }
2692
2693 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2694 // Rewriting all permissions section in the descriptor file
2695 $rewrite = checkExistComment($moduledescriptorfile, 1);
2696 if ($rewrite < 0) {
2697 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2698 } else {
2699 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightToAdd, '', '', 1);
2700 setEventMessages($langs->trans('PermissionAddedSuccesfuly'), null);
2701
2702 clearstatcache(true);
2703 if (function_exists('opcache_invalidate')) {
2704 opcache_reset(); // remove the include cache hell !
2705 }
2706 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2707 exit;
2708 }
2709 }
2710}
2711
2712
2713// Update permission
2714if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright') && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2715 $error = 0;
2716 // load class and check if right exist
2717 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2718 dol_include_once($pathtofile);
2719 $class = 'mod'.$module;
2720 $moduleobj = null;
2721 if (class_exists($class)) {
2722 try {
2723 $moduleobj = new $class($db);
2724 '@phan-var-force DolibarrModules $moduleobj';
2726 } catch (Exception $e) {
2727 $error++;
2728 dol_print_error($db, $e->getMessage());
2729 }
2730 }
2731 // verify information entered
2732 if (!GETPOST('label', 'alpha')) {
2733 $error++;
2734 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2735 }
2736 if (!GETPOST('permissionObj', 'alpha')) {
2737 $error++;
2738 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2739 }
2740
2741 $label = GETPOST('label', 'alpha');
2742 $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2743 $crud = GETPOST('crud', 'alpha');
2744
2745
2746 if ($label == "Read objects of $module" && $crud != "read") {
2747 $crud = "read";
2748 // $label = "Read objects of $module";
2749 }
2750 if ($label == "Create/Update objects of $module" && $crud != "write") {
2751 $crud = "write";
2752 // $label = "Create/Update objects of $module";
2753 }
2754 if ($label == "Delete objects of $module" && $crud != "delete") {
2755 $crud = "delete";
2756 // $label = "Delete objects of $module";
2757 }
2758
2759 if (is_object($moduleobj)) {
2760 $permissions = $moduleobj->rights;
2761 } else {
2762 $permissions = [];
2763 }
2764 $key = GETPOSTINT('counter') - 1;
2765 //get permission want to delete from permissions array
2766 if (array_key_exists($key, $permissions)) {
2767 $x1 = $permissions[$key][1];
2768 $x2 = $permissions[$key][4];
2769 $x3 = $permissions[$key][5];
2770 } else {
2771 $x1 = null;
2772 $x2 = null;
2773 $x3 = null;
2774 }
2775 //check existing object permission
2776 $counter = 0;
2777 $permsForObject = array();
2778 // $permissions = $moduleobj->rights; // Already fetched above
2779 $firstRight = 0;
2780 $existRight = 0;
2781 $allObject = array();
2782
2783 $countPerms = count($permissions);
2784 for ($i = 0; $i < $countPerms; $i++) {
2785 if ($permissions[$i][4] == $objectForPerms) {
2786 $counter++;
2787 if (count($permsForObject) < 3) {
2788 $permsForObject[] = $permissions[$i];
2789 }
2790 }
2791 $allObject[] = $permissions[$i][4];
2792 }
2793
2794 if ($label != $x1 && $crud != $x3) {
2795 $countPermsObj = count($permsForObject);
2796 for ($j = 0; $j < $countPermsObj; $j++) {
2797 if (in_array($label, $permsForObject[$j])) {
2798 $error++;
2799 setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($label), $langs->transnoentities($objectForPerms)), null, 'errors');
2800 }
2801 }
2802 }
2803
2804 if (!$error) {
2805 if (isModEnabled(strtolower($module))) {
2806 $result = unActivateModule(strtolower($module));
2807 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2808 if ($result) {
2809 setEventMessages($result, null, 'errors');
2810 }
2811 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2812 }
2813
2814 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2815 // rewriting all permissions after update permission needed
2816 $rewrite = checkExistComment($moduledescriptorfile, 1);
2817 if ($rewrite < 0) {
2818 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2819 } else {
2820 $rightUpdated = null; // I not set at this point
2821 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightUpdated, '', '', 2);
2822 setEventMessages($langs->trans('PermissionUpdatedSuccesfuly'), null);
2823 clearstatcache(true);
2824 if (function_exists('opcache_invalidate')) {
2825 opcache_reset(); // remove the include cache hell !
2826 }
2827 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2828 exit;
2829 }
2830 }
2831}
2832// Delete permission
2833if ($dirins && $action == 'confirm_deleteright' && !empty($module) && GETPOSTINT('permskey') /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2834 $error = 0;
2835 // load class and check if right exist
2836 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2837 dol_include_once($pathtofile);
2838 $class = 'mod'.$module;
2839 $moduleobj = null;
2840 if (class_exists($class)) {
2841 try {
2842 $moduleobj = new $class($db);
2843 '@phan-var-force DolibarrModules $moduleobj';
2845 } catch (Exception $e) {
2846 $error++;
2847 dol_print_error($db, $e->getMessage());
2848 }
2849 }
2850
2851 $permissions = $moduleobj->rights;
2852 $key = GETPOSTINT('permskey') - 1;
2853
2854 if (!$error) {
2855 // check if module is enabled
2856 if (isModEnabled(strtolower($module))) {
2857 $result = unActivateModule(strtolower($module));
2858 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2859 if ($result) {
2860 setEventMessages($result, null, 'errors');
2861 }
2862 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
2863 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2864 exit;
2865 }
2866
2867 // rewriting all permissions
2868 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2869 $rewrite = checkExistComment($moduledescriptorfile, 1);
2870 if ($rewrite < 0) {
2871 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Permissions"), "mod".$module."class.php"), null, 'warnings');
2872 } else {
2873 reWriteAllPermissions($moduledescriptorfile, $permissions, $key, null, '', '', 0);
2874 setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null);
2875
2876 clearstatcache(true);
2877 if (function_exists('opcache_invalidate')) {
2878 opcache_reset(); // remove the include cache hell !
2879 }
2880
2881 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2882 exit;
2883 }
2884 }
2885}
2886// Save file
2887if ($action == 'savefile' && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2888 $relofcustom = basename($dirins);
2889
2890 if ($relofcustom) {
2891 // Check that relative path ($file) start with name 'custom'
2892 if (!preg_match('/^'.$relofcustom.'/', $file)) {
2893 $file = $relofcustom.'/'.$file;
2894 }
2895
2896 $pathoffile = dol_buildpath($file, 0);
2897 $pathoffilebackup = dol_buildpath($file.'.back', 0);
2898
2899 // Save old version
2900 if (dol_is_file($pathoffile)) {
2901 dol_copy($pathoffile, $pathoffilebackup, '0', 1);
2902 }
2903
2904 $check = 'restricthtml';
2905 $srclang = dol_mimetype($pathoffile, '', 3);
2906 if ($srclang == 'md') {
2907 $check = 'restricthtml';
2908 }
2909 if ($srclang == 'lang') {
2910 $check = 'restricthtml';
2911 }
2912 if ($srclang == 'php') {
2913 $check = 'none';
2914 }
2915
2916 $content = GETPOST('editfilecontent', $check);
2917
2918 // Save file on disk
2919 if ($content) {
2920 dol_delete_file($pathoffile);
2921 $result = file_put_contents($pathoffile, $content);
2922 if ($result) {
2923 dolChmod($pathoffile, $newmask);
2924
2925 setEventMessages($langs->trans("FileSaved"), null);
2926 } else {
2927 setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
2928 }
2929 } else {
2930 setEventMessages($langs->trans("ContentCantBeEmpty"), null, 'errors');
2931 //$action='editfile';
2932 $error++;
2933 }
2934 }
2935}
2936
2937// Enable module
2938if ($action == 'set' && $user->admin /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2939 $param = '';
2940 if ($module) {
2941 $param .= '&module='.urlencode($module);
2942 }
2943
2944 $param .= '&tab='.urlencode($tab);
2945 $param .= '&tabobj='.urlencode($tabobj);
2946
2947 $value = GETPOST('value', 'alpha');
2948 $resarray = activateModule($value, 1, 0);
2949 if (!empty($resarray['errors'])) {
2950 setEventMessages('', $resarray['errors'], 'errors');
2951 } else {
2952 //var_dump($resarray);exit;
2953 if ($resarray['nbperms'] > 0) {
2954 $tmpsql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1";
2955 $resqltmp = $db->query($tmpsql);
2956 if ($resqltmp) {
2957 $obj = $db->fetch_object($resqltmp);
2958 //var_dump($obj->nb);exit;
2959 if ($obj && $obj->nb > 1) {
2960 $msg = $langs->trans('ModuleEnabledAdminMustCheckRights');
2961 setEventMessages($msg, null, 'warnings');
2962 }
2963 } else {
2965 }
2966 }
2967 }
2968 header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2969 exit;
2970}
2971
2972// Disable module
2973if ($action == 'reset' && $user->admin /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2974 $param = '';
2975 if ($module) {
2976 $param .= '&module='.urlencode($module);
2977 }
2978 $param .= '&tab='.urlencode($tab);
2979 $param .= '&tabobj='.urlencode($tabobj);
2980
2981 $value = GETPOST('value', 'alpha');
2982 $result = unActivateModule(strtolower($value));
2983 if ($result) {
2984 setEventMessages($result, null, 'errors');
2985 }
2986 header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2987 exit;
2988}
2989
2990// Delete menu
2991if ($dirins && $action == 'confirm_deletemenu' && GETPOSTINT('menukey') /* && $user->hasRight("modulebuilder", "run") // already checked */) {
2992 // check if module is enabled
2993 if (isModEnabled(strtolower($module))) {
2994 $result = unActivateModule(strtolower($module));
2995 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
2996 if ($result) {
2997 setEventMessages($result, null, 'errors');
2998 }
2999 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
3000 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3001 exit;
3002 }
3003 // load class and check if menu exist
3004 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3005 dol_include_once($pathtofile);
3006 $class = 'mod'.$module;
3007 $moduleobj = null;
3008 if (class_exists($class)) {
3009 try {
3010 $moduleobj = new $class($db);
3011 '@phan-var-force DolibarrModules $moduleobj';
3013 } catch (Exception $e) {
3014 $error++;
3015 dol_print_error($db, $e->getMessage());
3016 }
3017 }
3018 // get all objects and convert value to lower case for compare
3019 $dir = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
3020 $destdir = $dir.'/'.strtolower($module);
3021 $objects = dolGetListOfObjectClasses($destdir);
3022 $result = array_map('strtolower', $objects);
3023
3024 $menus = $moduleobj->menu;
3025 $key = GETPOSTINT('menukey');
3026 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
3027
3028 $checkcomment = checkExistComment($moduledescriptorfile, 0);
3029 if ($checkcomment < 0) {
3030 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
3031 } else {
3032 if ($menus[$key]['fk_menu'] === 'fk_mainmenu='.strtolower($module)) {
3033 if (in_array(strtolower($menus[$key]['leftmenu']), $result)) {
3034 reWriteAllMenus($moduledescriptorfile, $menus, $menus[$key]['leftmenu'], $key, -1);
3035 } else {
3036 reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
3037 }
3038 } else {
3039 reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
3040 }
3041
3042 clearstatcache(true);
3043 if (function_exists('opcache_invalidate')) {
3044 opcache_reset(); // remove the include cache hell !
3045 }
3046
3047 setEventMessages($langs->trans('MenuDeletedSuccessfuly'), null);
3048 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3049 exit;
3050 }
3051}
3052
3053// Add menu in module without initial object
3054if ($dirins && $action == 'addmenu' && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
3055 // check if module is enabled
3056 if (isModEnabled(strtolower($module))) {
3057 $result = unActivateModule(strtolower($module));
3058 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
3059 if ($result) {
3060 setEventMessages($result, null, 'errors');
3061 }
3062 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
3063 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3064 exit;
3065 }
3066 $error = 0;
3067
3068 // load class and check if right exist
3069 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3070 dol_include_once($pathtofile);
3071 $class = 'mod'.$module;
3072 $moduleobj = null;
3073 if (class_exists($class)) {
3074 try {
3075 $moduleobj = new $class($db);
3076 '@phan-var-force DolibarrModules $moduleobj';
3078 } catch (Exception $e) {
3079 $error++;
3080 dol_print_error($db, $e->getMessage());
3081 }
3082 }
3083 // get all menus
3084 $menus = $moduleobj->menu;
3085
3086 //verify fields required
3087 if (!GETPOST('type', 'alpha')) {
3088 $error++;
3089 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
3090 }
3091 if (!GETPOST('titre', 'alpha')) {
3092 $error++;
3093 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Title")), null, 'errors');
3094 }
3095 if (!GETPOST('user', 'alpha')) {
3096 $error++;
3097 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("DetailUser")), null, 'errors');
3098 }
3099 if (!GETPOST('url', 'alpha')) {
3100 $error++;
3101 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Url")), null, 'errors');
3102 }
3103 if (!empty(GETPOST('target'))) {
3104 $targets = array('_blank','_self','_parent','_top','');
3105 if (!in_array(GETPOST('target'), $targets)) {
3106 $error++;
3107 setEventMessages($langs->trans("ErrorFieldValue", $langs->transnoentities("target")), null, 'errors');
3108 }
3109 }
3110
3111
3112 // check if title or url already exist in menus
3113
3114 foreach ($menus as $menu) {
3115 if (!empty(GETPOST('url')) && GETPOST('url') == $menu['url']) {
3116 $error++;
3117 setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("url")), null, 'errors');
3118 break;
3119 }
3120 if (strtolower(GETPOST('titre')) == strtolower($menu['titre'])) {
3121 $error++;
3122 setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("titre")), null, 'errors');
3123 break;
3124 }
3125 }
3126
3127 if (GETPOST('type', 'alpha') == 'left' && !empty(GETPOST('lefmenu', 'alpha'))) {
3128 if (!str_contains(GETPOST('leftmenu'), strtolower($module))) {
3129 $error++;
3130 setEventMessages($langs->trans("WarningFieldsMustContains", $langs->transnoentities("LeftmenuId")), null, 'errors');
3131 }
3132 }
3133 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
3134 $destdir = $dirins.'/'.strtolower($module);
3135 $objects = dolGetListOfObjectClasses($destdir);
3136
3137 if (GETPOST('type', 'alpha') == 'left') {
3138 if (empty(GETPOST('leftmenu')) && count($objects) > 0) {
3139 $error++;
3140 setEventMessages($langs->trans("ErrorCoherenceMenu", $langs->transnoentities("LeftmenuId"), $langs->transnoentities("type")), null, 'errors');
3141 }
3142 }
3143 if (GETPOST('type', 'alpha') == 'top') {
3144 $error++;
3145 setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
3146 }
3147
3148 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
3149 if (!$error) {
3150 //stock forms in array
3151 $menuToAdd = array(
3152 'fk_menu' => GETPOST('fk_menu', 'alpha'),
3153 'type' => GETPOST('type', 'alpha'),
3154 'titre' => ucfirst(GETPOST('titre', 'alpha')),
3155 'prefix' => '',
3156 'mainmenu' => GETPOST('mainmenu', 'alpha'),
3157 'leftmenu' => GETPOST('leftmenu', 'alpha'),
3158 'url' => GETPOST('url', 'alpha'),
3159 'langs' => strtolower($module)."@".strtolower($module),
3160 'position' => '',
3161 'enabled' => GETPOST('enabled', 'alpha'),
3162 'perms' => '$user->hasRight("'.strtolower($module).'", "'.GETPOST('objects', 'alpha').'", "'.GETPOST('perms', 'alpha').'")',
3163 'target' => GETPOST('target', 'alpha'),
3164 'user' => GETPOSTINT('user'),
3165 );
3166
3167 if (GETPOST('type') == 'left') {
3168 unset($menuToAdd['prefix']);
3169 if (empty(GETPOST('fk_menu'))) {
3170 $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha');
3171 } else {
3172 $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha').',fk_leftmenu='.GETPOST('fk_menu');
3173 }
3174 }
3175 if (GETPOST('enabled') == '1') {
3176 $menuToAdd['enabled'] = 'isModEnabled("'.strtolower($module).'")';
3177 } else {
3178 $menuToAdd['enabled'] = "0";
3179 }
3180 if (empty(GETPOST('objects'))) {
3181 $menuToAdd['perms'] = '1';
3182 }
3183
3184 $checkcomment = checkExistComment($moduledescriptorfile, 0);
3185 if ($checkcomment < 0) {
3186 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
3187 } else {
3188 // Write all menus
3189 $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuToAdd, null, 1);
3190
3191 clearstatcache(true);
3192 if (function_exists('opcache_invalidate')) {
3193 opcache_reset();
3194 }
3195 /*if ($result < 0) {
3196 setEventMessages($langs->trans('ErrorMenuExistValue'), null, 'errors');
3197 header("Location: ".$_SERVER["PHP_SELF"].'?action=editmenu&token='.newToken().'&menukey='.urlencode($key+1).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.($key+1));
3198 exit;
3199 }*/
3200
3201 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3202 setEventMessages($langs->trans('MenuAddedSuccesfuly'), null);
3203 exit;
3204 }
3205 }
3206}
3207
3208// Modify a menu entry
3209if ($dirins && $action == "update_menu" && GETPOSTINT('menukey') && GETPOST('tabobj') /* && $user->hasRight("modulebuilder", "run") // already checked */) {
3210 $objectname = GETPOST('tabobj');
3211 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
3212 $destdir = $dirins.'/'.strtolower($module);
3213 $objects = dolGetListOfObjectClasses($destdir);
3214
3215 if (empty($cancel)) {
3216 if (isModEnabled(strtolower($module))) {
3217 $result = unActivateModule(strtolower($module));
3218 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
3219 if ($result) {
3220 setEventMessages($result, null, 'errors');
3221 }
3222 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
3223 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3224 exit;
3225 }
3226 $error = 0;
3227 // for loading class and the menu wants to modify
3228 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3229 dol_include_once($pathtofile);
3230 $class = 'mod'.$module;
3231 $moduleobj = null;
3232 if (class_exists($class)) {
3233 try {
3234 $moduleobj = new $class($db);
3235 '@phan-var-force DolibarrModules $moduleobj';
3237 } catch (Exception $e) {
3238 $error++;
3239 dol_print_error($db, $e->getMessage());
3240 }
3241 }
3242 $menus = $moduleobj->menu;
3243 $key = GETPOSTINT('menukey') - 1;
3244
3245 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
3246 //stock forms in array
3247 $menuModify = array(
3248 'fk_menu' => GETPOST('fk_menu', 'alpha'),
3249 'type' => GETPOST('type', 'alpha'),
3250 'titre' => ucfirst(GETPOST('titre', 'alpha')),
3251 'prefix' => '',
3252 'mainmenu' => GETPOST('mainmenu', 'alpha'),
3253 'leftmenu' => $menus[$key]['leftmenu'],
3254 'url' => GETPOST('url', 'alpha'),
3255 'langs' => strtolower($module)."@".strtolower($module),
3256 'position' => '',
3257 'enabled' => GETPOST('enabled', 'alpha'),
3258 'perms' => GETPOST('perms', 'alpha'),
3259 'target' => GETPOST('target', 'alpha'),
3260 'user' => GETPOSTINT('user'),
3261 );
3262 if (!empty(GETPOST('fk_menu')) && GETPOST('fk_menu') != $menus[$key]['fk_menu']) {
3263 $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu').',fk_leftmenu='.GETPOST('fk_menu');
3264 } elseif (GETPOST('fk_menu') == $menus[$key]['fk_menu']) {
3265 $menuModify['fk_menu'] = $menus[$key]['fk_menu'];
3266 } else {
3267 $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu');
3268 }
3269 if ($menuModify['enabled'] === '') {
3270 $menuModify['enabled'] = '1';
3271 }
3272 if ($menuModify['perms'] === '') {
3273 $menuModify['perms'] = '1';
3274 }
3275
3276 if (GETPOST('type', 'alpha') == 'top') {
3277 $error++;
3278 setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
3279 }
3280
3281 if (!$error) {
3282 //update menu
3283 $checkComment = checkExistComment($moduledescriptorfile, 0);
3284
3285 if ($checkComment < 0) {
3286 setEventMessages($langs->trans("WarningCommentNotFound", $langs->trans("Menus"), "mod".$module."class.php"), null, 'warnings');
3287 } else {
3288 // Write all menus
3289 $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuModify, $key, 2);
3290
3291 clearstatcache(true);
3292 if (function_exists('opcache_invalidate')) {
3293 opcache_reset();
3294 }
3295
3296 if ($result < 0) {
3297 setEventMessages($langs->trans('ErrorMenuExistValue'), null, 'errors');
3298 //var_dump($_SESSION);exit;
3299 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));
3300 exit;
3301 }
3302
3303 setEventMessages($langs->trans('MenuUpdatedSuccessfuly'), null);
3304 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3305 exit;
3306 }
3307 }
3308 } else {
3309 $_POST['type'] = ''; // TODO Use a var here and later
3310 $_POST['titre'] = '';
3311 $_POST['fk_menu'] = '';
3312 $_POST['leftmenu'] = '';
3313 $_POST['url'] = '';
3314 }
3315}
3316
3317// update properties description of module
3318if ($dirins && $action == "update_props_module" && !empty(GETPOST('keydescription', 'alpha')) && empty($cancel) /* && $user->hasRight("modulebuilder", "run") // already checked */) {
3319 if (isModEnabled(strtolower($module))) {
3320 $result = unActivateModule(strtolower($module));
3321 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
3322 if ($result) {
3323 setEventMessages($result, null, 'errors');
3324 }
3325 setEventMessages($langs->trans('WarningModuleNeedRefresh', $langs->transnoentities($module)), null, 'warnings');
3326 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
3327 exit;
3328 }
3329 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3330 $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
3331 $modulelogfile = $dirins.'/'.strtolower($module).'/ChangeLog.md';
3332
3333 dol_include_once($pathtofile);
3334
3335 $class = 'mod'.$module;
3336 $moduleobj = null;
3337 if (class_exists($class)) {
3338 try {
3339 $moduleobj = new $class($db);
3340 '@phan-var-force DolibarrModules $moduleobj';
3342 } catch (Exception $e) {
3343 $error++;
3344 dol_print_error($db, $e->getMessage());
3345 }
3346 }
3347
3348 $keydescription = GETPOST('keydescription', 'alpha');
3349 switch ($keydescription) {
3350 case 'desc':
3351 $propertyToUpdate = 'description';
3352 break;
3353 case 'version':
3354 case 'family':
3355 case 'picto':
3356 case 'editor_name':
3357 case 'editor_url':
3358 $propertyToUpdate = $keydescription;
3359 break;
3360 default:
3361 $error = GETPOST('keydescription');
3362 break;
3363 }
3364
3365 if (isset($propertyToUpdate) && !empty(GETPOST('propsmodule'))) {
3366 $newValue = GETPOST('propsmodule');
3367 $patternToFindLine = '^\s*\$this->'.$propertyToUpdate.'\s*='; // Must be a regex string
3368 $newLine = "\t\t\$this->$propertyToUpdate = '$newValue';\n"; // Must a real string
3369
3370 $fileLines = file($moduledescriptorfile); // Get each line of file into an array
3371 $error = 0;
3372 $changedone = 0;
3373 foreach ($fileLines as &$line) {
3374 if (preg_match('/'.$patternToFindLine.'/', $line)) {
3375 $result = dolReplaceInFile($moduledescriptorfile, array($line => $newLine));
3376 if ($result > 0) {
3377 $changedone++;
3378 } elseif ($result <= -1) {
3379 $langs->load("errors");
3380 setEventMessages($langs->trans('ErrorFailToEditFile', $moduledescriptorfile), null, 'warnings');
3381 break;
3382 }
3383 break;
3384 }
3385 }
3386
3387 // To complete also the ChangeLogif we update the version
3388 if ($changedone && $propertyToUpdate === 'version') {
3389 dolReplaceInFile($modulelogfile, array("## ".$moduleobj->$propertyToUpdate => $newValue));
3390 }
3391
3392 clearstatcache(true);
3393 if (function_exists('opcache_invalidate')) {
3394 opcache_reset();
3395 }
3396 if ($changedone) {
3397 setEventMessages($langs->trans('PropertyModuleUpdated', $propertyToUpdate), null);
3398 } else {
3399 setEventMessages($langs->trans('NothingProcessed'), null, 'warnings');
3400 }
3401
3402 header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=description&module='.$module);
3403 exit;
3404 }
3405}
3406
3407
3408/*
3409 * View
3410 */
3411
3412$form = new Form($db);
3413$formadmin = new FormAdmin($db);
3414
3415// Set dir where external modules are installed
3416if (!dol_is_dir($dirins)) {
3417 dol_mkdir($dirins);
3418}
3419$dirins_ok = (dol_is_dir($dirins));
3420
3421$help_url = '';
3422$morejs = array(
3423 '/includes/ace/src/ace.js',
3424 '/includes/ace/src/ext-statusbar.js',
3425 '/includes/ace/src/ext-language_tools.js',
3426 //'/includes/ace/src/ext-chromevox.js'
3427);
3428$morecss = array();
3429
3430llxHeader('', $langs->trans("ModuleBuilder"), $help_url, '', 0, 0, $morejs, $morecss, '', 'classforhorizontalscrolloftabs');
3431
3432
3433$text = $langs->trans("ModuleBuilder");
3434
3435$morehtmlright = '<a href="'.DOL_URL_ROOT.'/admin/tools/ui/index.php" target="_blank" rel="noopener">'.img_picto('', 'book', 'class="pictofixedwidth"').$langs->trans("UxComponentsDoc").'</a>';
3436
3437print load_fiche_titre($text, $morehtmlright, 'title_setup');
3438
3439print '<div class="info hideonsmartphone">';
3440print $langs->trans("ModuleBuilderDesc", 'https://wiki.dolibarr.org/index.php/Module_development').'</span>';
3441print '</div>';
3442
3443
3444$message = '';
3445if (!$dirins) {
3446 $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
3447 $allowfromweb = -1;
3448} else {
3449 if ($dirins_ok) {
3450 if (!is_writable(dol_osencode($dirins))) {
3451 $langs->load("errors");
3452 $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins));
3453 $allowfromweb = 0;
3454 }
3455 } else {
3456 $message = info_admin($langs->trans("NotExistsDirect", $dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
3457 $allowfromweb = 0;
3458 }
3459}
3460if ($message) {
3461 print $message;
3462}
3463
3464//print $langs->trans("ModuleBuilderDesc3", count($listofmodules), $FILEFLAG).'<br>';
3465$infomodulesfound = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', $langs->trans("ModuleBuilderDesc3", count($listofmodules)).'<br><br>'.$langs->trans("ModuleBuilderDesc4", $FILEFLAG).'<br>'.$textforlistofdirs).'</div>';
3466
3467
3468
3469$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
3470$allowonlineinstall = true;
3471if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
3472 $allowonlineinstall = false;
3473}
3474if (empty($allowonlineinstall)) {
3475 if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
3476 // Show clean message
3477 $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'));
3478 } else {
3479 // Show technical message
3480 $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'), 0, 0, '1', 'warning');
3481 }
3482
3483 print $message;
3484
3485 llxFooter();
3486 exit(0);
3487}
3488
3489
3490// Load module descriptor
3491$error = 0;
3493
3494
3495if (!empty($module) && $module != 'initmodule' && $module != 'deletemodule') {
3496 $modulelowercase = strtolower($module);
3497 $loadclasserrormessage = '';
3498
3499 $class = null;
3500 // Load module
3501 try {
3502 $fullpathdirtodescriptor = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3503
3504 //throw(new Exception());
3505 dol_include_once($fullpathdirtodescriptor);
3506
3507 $class = 'mod'.$module;
3508 } catch (Throwable $e) { // This is called in PHP 7 only (includes Error and Exception)
3509 $loadclasserrormessage = $e->getMessage()."<br>\n";
3510 $loadclasserrormessage .= 'File: '.$e->getFile()."<br>\n";
3511 $loadclasserrormessage .= 'Line: '.$e->getLine()."<br>\n";
3512 }
3513
3514 $moduleobj = null;
3515 if (class_exists($class)) {
3516 try {
3517 $moduleobj = new $class($db);
3518 '@phan-var-force DolibarrModules $moduleobj';
3520 } catch (Exception $e) {
3521 $error++;
3522 print $e->getMessage();
3523 }
3524 } else {
3525 if (empty($forceddirread)) {
3526 $error++;
3527 }
3528 $langs->load("errors");
3529 print '<!-- ErrorFailedToLoadModuleDescriptorForXXX -->';
3530 print img_warning('').' '.$langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
3531 print $loadclasserrormessage;
3532 print '<br>';
3533 }
3534}
3535
3536
3537// Tabs for all modules
3538$head = array();
3539$h = 0;
3540
3541$head[$h][0] = $_SERVER["PHP_SELF"].'?module=initmodule';
3542$head[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewModule").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
3543$head[$h][2] = 'initmodule';
3544$h++;
3545
3546$linktoenabledisable = '';
3547
3548if (/* is_array($listofmodules) && */ count($listofmodules) > 0) {
3549 // Define $linktoenabledisable
3550 $modulelowercase = strtolower($module);
3551
3552 $param = '';
3553 if ($module) {
3554 $param .= '&module='.urlencode($module);
3555 }
3556
3557 $param .= '&tab='.urlencode($tab);
3558 $param .= '&tabobj='.urlencode($tabobj);
3559
3560 $urltomodulesetup = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?search_keyword='.urlencode($module).'">'.$langs->trans('Home').'-'.$langs->trans("Setup").'-'.$langs->trans("Modules").'</a>';
3561
3562 // Define $linktoenabledisable to show after module title
3563 if (isModEnabled($modulelowercase)) { // If module is already activated
3564 $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=reset&token='.newToken().'&value=mod'.$module.$param.'">';
3565 $linktoenabledisable .= img_picto($langs->trans("Warning").' : '.$langs->trans("ModuleIsLive"), 'switch_on', '', 0, 0, 0, '', 'warning valignmiddle', 1);
3566 $linktoenabledisable .= '</a>';
3567
3568 //$linktoenabledisable .= $form->textwithpicto('', $langs->trans("Warning").' : '.$langs->trans("ModuleIsLive"), -1, 'warning');
3569
3570 $objMod = $moduleobj;
3571 $backtourlparam = '';
3572 $backtourlparam .= ($backtourlparam ? '&' : '?').'module='.$module; // No urlencode here, done later
3573 $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later
3574 $backtourl = $_SERVER["PHP_SELF"].$backtourlparam;
3575
3576 $regs = array();
3577 if (is_array($objMod->config_page_url)) {
3578 $i = 0;
3579 foreach ($objMod->config_page_url as $page) {
3580 $urlpage = $page;
3581 if ($i++) {
3582 $linktoenabledisable .= ' <a class="valignmiddle" href="'.$urlpage.'" title="'.$langs->trans($page).'">'.img_picto(ucfirst($page), "setup").'</a>';
3583 // print '<a href="'.$page.'">'.ucfirst($page).'</a>&nbsp;';
3584 } else {
3585 if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) {
3586 $urltouse = dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1);
3587 $linktoenabledisable .= ' <a class="valignmiddle" 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"', 0, 0, 0, '', '').'</a>';
3588 } else {
3589 // Case standard admin page (not a page provided by the
3590 // module but a page provided by dolibarr)
3591 $urltouse = DOL_URL_ROOT.'/admin/'.$urlpage;
3592 $linktoenabledisable .= ' <a class="valignmiddle" 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"', 0, 0, 0, '', '').'</a>';
3593 }
3594 }
3595 }
3596 } elseif (preg_match('/^([^@]+)@([^@]+)$/i', $objMod->config_page_url, $regs)) {
3597 $linktoenabledisable .= ' &nbsp; <a class="valignmiddle" 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"', 0, 0, 0, '', '').'</a>';
3598 }
3599 } else {
3600 if (is_object($moduleobj)) {
3601 $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=set&token='.newToken().'&value=mod'.$module.$param.'">';
3602 $linktoenabledisable .= img_picto($langs->trans("ModuleIsNotActive", $urltomodulesetup), 'switch_off', 'style="padding-right: 8px"', 0, 0, 0, '', 'classfortooltip valignmiddle', 1);
3603 $linktoenabledisable .= "</a>\n";
3604 }
3605 }
3606
3607 // Loop to show tab of each module
3608 foreach ($listofmodules as $tmpmodule => $tmpmodulearray) {
3609 $head[$h][0] = $_SERVER["PHP_SELF"].'?module='.$tmpmodulearray['modulenamewithcase'].($forceddirread ? '@'.$dirread : '');
3610 $head[$h][1] = $tmpmodulearray['modulenamewithcase'];
3611 $head[$h][2] = $tmpmodulearray['modulenamewithcase'];
3612
3613 if ($tmpmodulearray['modulenamewithcase'] == $module) {
3614 $head[$h][4] = '<span class="inline-block valignmiddle">'.$linktoenabledisable.'</span>';
3615 }
3616
3617 $h++;
3618 }
3619}
3620
3621$head[$h][0] = $_SERVER["PHP_SELF"].'?module=deletemodule';
3622$head[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
3623$head[$h][2] = 'deletemodule';
3624$h++;
3625
3626
3627print dol_get_fiche_head($head, $module, '', -1, '', 0, $infomodulesfound, '', 8); // Modules
3628
3629if ($module == 'initmodule') {
3630 // New module
3631 print '<!-- section init module -->'."\n";
3632 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3633 print '<input type="hidden" name="token" value="'.newToken().'">';
3634 print '<input type="hidden" name="action" value="initmodule">';
3635 print '<input type="hidden" name="module" value="initmodule">';
3636
3637 //print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc2", 'conf/conf.php', $newdircustom).'</span><br>';
3638 print '<br>';
3639
3640 print '<div class="tagtable table-border">';
3641
3642 print '<div class="tagtr"><div class="tagtd paddingright">';
3643 print '<span class="opacitymedium">'.$langs->trans("IdModule").'</span>';
3644 print '</div><div class="tagtd">';
3645 print '<input type="number" min="100000" name="idmodule" class="width100" value="500000">';
3646 print '<span class="opacitymedium small">';
3647 print ' &nbsp; &nbsp; ';
3648 print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info&hidetitle=1', '', '');
3649 print ' - ';
3650 print '<a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>';
3651 print '</span>';
3652 print '</div></div>';
3653
3654 print '<div class="tagtr"><div class="tagtd paddingright">';
3655 print '<span class="opacitymedium fieldrequired">'.$langs->trans("ModuleName").'</span>';
3656 print '</div><div class="tagtd">';
3657 print '<input type="text" name="modulename" value="'.dol_escape_htmltag($modulename).'" autofocus>';
3658 print ' '.$form->textwithpicto('', $langs->trans("EnterNameOfModuleDesc"));
3659 print '</div></div>';
3660
3661 print '<div class="tagtr"><div class="tagtd paddingright">';
3662 print '<span class="opacitymedium">'.$langs->trans("Description").'</span>';
3663 print '</div><div class="tagtd">';
3664 print '<input type="text" name="description" value="" class="minwidth500"><br>';
3665 print '</div></div>';
3666
3667 print '<div class="tagtr"><div class="tagtd paddingright">';
3668 print '<span class="opacitymedium">'.$langs->trans("Version").'</span>';
3669 print '</div><div class="tagtd">';
3670 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")).'">';
3671 print '</div></div>';
3672
3673 print '<div class="tagtr"><div class="tagtd paddingright">';
3674 print '<span class="opacitymedium">'.$langs->trans("Family").'</span>';
3675 print '</div><div class="tagtd">';
3676 print '<select name="family" id="family" class="minwidth400">';
3677 $arrayoffamilies = array(
3678 'hr' => "ModuleFamilyHr",
3679 'crm' => "ModuleFamilyCrm",
3680 'srm' => "ModuleFamilySrm",
3681 'financial' => 'ModuleFamilyFinancial',
3682 'products' => 'ModuleFamilyProducts',
3683 'projects' => 'ModuleFamilyProjects',
3684 'ecm' => 'ModuleFamilyECM',
3685 'technic' => 'ModuleFamilyTechnic',
3686 'portal' => 'ModuleFamilyPortal',
3687 'interface' => 'ModuleFamilyInterface',
3688 'base' => 'ModuleFamilyBase',
3689 'other' => 'ModuleFamilyOther'
3690 );
3691 foreach ($arrayoffamilies as $key => $value) {
3692 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>';
3693 }
3694 print '</select>';
3695 print ajax_combobox("family");
3696 print '</div></div>';
3697
3698 print '<div class="tagtr"><div class="tagtd paddingright">';
3699 print '<span class="opacitymedium">'.$langs->trans("Picto").'</span>';
3700 print '</div><div class="tagtd">';
3701 print '<input type="text" name="idpicto" value="'.(GETPOSTISSET('idpicto') ? GETPOST('idpicto') : getDolGlobalString('MODULEBUILDER_DEFAULTPICTO', 'fa-file')).'" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
3702 print $form->textwithpicto('', $langs->trans("Example").': fa-file, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
3703
3704 print ' &nbsp; &nbsp; ';
3705
3706 print '<span class="opacitymedium small">';
3707 print dolButtonToOpenUrlInDialogPopup('popup_picto_id', $langs->transnoentitiesnoconv("DocIconsList"), $langs->transnoentitiesnoconv("DocIconsList"), '/admin/tools/ui/components/icons.php?hidenavmenu=1&displayMode=icon-only&mode=no-btn#img-picto-section-list', '', '');
3708 print '</span>';
3709
3710 print '</div></div>';
3711
3712 print '<div class="tagtr"><div class="tagtd paddingright">';
3713 print '<span class="opacitymedium">'.$langs->trans("EditorName").'</span>';
3714 print '</div><div class="tagtd">';
3715 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")).'" spellcheck="false"><br>';
3716 print '</div></div>';
3717
3718 print '<div class="tagtr"><div class="tagtd paddingright">';
3719 print '<span class="opacitymedium">'.$langs->trans("EditorUrl").'</span>';
3720 print '</div><div class="tagtd">';
3721 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")).'" spellcheck="false"><br>';
3722 print '</div></div>';
3723
3724 print '</div>'; // End div tagtable
3725
3726 print '<br><center>';
3727 print '<input type="submit" class="button" name="create" value="'.dol_escape_htmltag($langs->trans("Create")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3728 print '</center>';
3729 print '</form>';
3730} elseif ($module == 'deletemodule') {
3731 print '<!-- Form to init a module -->'."\n";
3732 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="delete">';
3733 print '<input type="hidden" name="token" value="'.newToken().'">';
3734 print '<input type="hidden" name="action" value="confirm_deletemodule">';
3735 print '<input type="hidden" name="module" value="deletemodule">';
3736
3737 print $langs->trans("EnterNameOfModuleToDeleteDesc").'<br><br>';
3738
3739 print '<input type="text" name="module" placeholder="'.dol_escape_htmltag($langs->trans("ModuleKey")).'" value="" autofocus>';
3740 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Delete").'"'.($dirins ? '' : ' disabled="disabled"').'>';
3741 print '</form>';
3742} elseif (!empty($module) && $modulelowercase !== null) {
3743 // Tabs for module
3744 if (!$error) {
3745 $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
3746 $destdir = $dirread.'/'.strtolower($module);
3747 $objects = dolGetListOfObjectClasses($destdir);
3748 $diroflang = dol_buildpath($modulelowercase, 0)."/langs";
3749 $countLangs = countItemsInDirectory($diroflang, 2);
3750 $countDictionaries = (!empty($moduleobj->dictionaries) ? count($moduleobj->dictionaries['tabname']) : 0);
3751 $countRights = count($moduleobj->rights);
3752 $countMenus = count($moduleobj->menu);
3753 $countTriggers = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/triggers");
3754 $countWidgets = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/boxes");
3755 $countEmailingSelectors = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/modules/mailings");
3756 $countCss = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/css");
3757 $countJs = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/js");
3758 $countCLI = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/scripts");
3759 $hasDoc = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/doc");
3760 //var_dump($moduleobj->dictionaries);exit;
3761 $head2 = array();
3762 $h = 0;
3763
3764 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=description&module='.$module.($forceddirread ? '@'.$dirread : '');
3765 $head2[$h][1] = $langs->trans("Description");
3766 $head2[$h][2] = 'description';
3767 $h++;
3768
3769 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '');
3770 $head2[$h][1] = ((!is_array($objects) || count($objects) <= 0) ? $langs->trans("Objects") : $langs->trans("Objects").'<span class="marginleftonlyshort badge">'.count($objects)."</span>");
3771 $head2[$h][2] = 'objects';
3772 $h++;
3773
3774 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=languages&module='.$module.($forceddirread ? '@'.$dirread : '');
3775 $head2[$h][1] = ($countLangs <= 0 ? $langs->trans("Languages") : $langs->trans("Languages").'<span class="marginleftonlyshort badge">'.$countLangs."</span>");
3776 $head2[$h][2] = 'languages';
3777 $h++;
3778
3779 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=permissions&module='.$module.($forceddirread ? '@'.$dirread : '');
3780 $head2[$h][1] = ($countRights <= 0 ? $langs->trans("Permissions") : $langs->trans("Permissions").'<span class="marginleftonlyshort badge">'.$countRights."</span>");
3781 $head2[$h][2] = 'permissions';
3782 $h++;
3783
3784 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '');
3785 $head2[$h][1] = ($countDictionaries == 0 ? $langs->trans("Dictionaries") : $langs->trans('Dictionaries').'<span class="marginleftonlyshort badge">'.$countDictionaries."</span>");
3786 $head2[$h][2] = 'dictionaries';
3787 $h++;
3788
3789 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=tabs&module='.$module.($forceddirread ? '@'.$dirread : '');
3790 $head2[$h][1] = $langs->trans("Tabs");
3791 $head2[$h][2] = 'tabs';
3792 $h++;
3793
3794 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=menus&module='.$module.($forceddirread ? '@'.$dirread : '');
3795 $head2[$h][1] = ($countMenus <= 0 ? $langs->trans("Menus") : $langs->trans("Menus").'<span class="marginleftonlyshort badge">'.$countMenus."</span>");
3796 $head2[$h][2] = 'menus';
3797 $h++;
3798
3799 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=hooks&module='.$module.($forceddirread ? '@'.$dirread : '');
3800 $head2[$h][1] = $langs->trans("Hooks");
3801 $head2[$h][2] = 'hooks';
3802 $h++;
3803
3804 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=triggers&module='.$module.($forceddirread ? '@'.$dirread : '');
3805 $head2[$h][1] = ($countTriggers <= 0 ? $langs->trans("Triggers") : $langs->trans("Triggers").'<span class="marginleftonlyshort badge">'.$countTriggers."</span>");
3806 $head2[$h][2] = 'triggers';
3807 $h++;
3808
3809 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=widgets&module='.$module.($forceddirread ? '@'.$dirread : '');
3810 $head2[$h][1] = ($countWidgets <= 0 ? $langs->trans("Widgets") : $langs->trans("Widgets").'<span class="marginleftonlyshort badge">'.$countWidgets."</span>");
3811 $head2[$h][2] = 'widgets';
3812 $h++;
3813
3814 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=emailings&module='.$module.($forceddirread ? '@'.$dirread : '');
3815 $head2[$h][1] = ($countEmailingSelectors <= 0 ? $langs->trans("EmailingSelectors") : $langs->trans("EmailingSelectors").'<span class="marginleftonlyshort badge">'.$countEmailingSelectors."</span>");
3816 $head2[$h][2] = 'emailings';
3817 $h++;
3818
3819 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=exportimport&module='.$module.($forceddirread ? '@'.$dirread : '');
3820 $head2[$h][1] = $langs->trans("ImportExportProfiles");
3821 $head2[$h][2] = 'exportimport';
3822 $h++;
3823
3824 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=css&module='.$module.($forceddirread ? '@'.$dirread : '');
3825 $head2[$h][1] = ($countCss <= 0 ? $langs->trans("CSS") : $langs->trans("CSS")." (".$countCss.")");
3826 $head2[$h][2] = 'css';
3827 $h++;
3828
3829 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=js&module='.$module.($forceddirread ? '@'.$dirread : '');
3830 $head2[$h][1] = ($countJs <= 0 ? $langs->trans("JS") : $langs->trans("JS").'<span class="marginleftonlyshort badge">'.$countJs."</span>");
3831 $head2[$h][2] = 'js';
3832 $h++;
3833
3834 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cli&module='.$module.($forceddirread ? '@'.$dirread : '');
3835 $head2[$h][1] = ($countCLI <= 0 ? $langs->trans("CLI") : $langs->trans("CLI").'<span class="marginleftonlyshort badge">'.$countCLI."</span>");
3836 $head2[$h][2] = 'cli';
3837 $h++;
3838
3839 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cron&module='.$module.($forceddirread ? '@'.$dirread : '');
3840 $head2[$h][1] = $langs->trans("CronList");
3841 $head2[$h][2] = 'cron';
3842 $h++;
3843
3844 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=specifications&module='.$module.($forceddirread ? '@'.$dirread : '');
3845 $head2[$h][1] = ($hasDoc <= 0 ? $langs->trans("Documentation") : $langs->trans("Documentation").'<span class="marginleftonlyshort badge">'.$hasDoc."</span>");
3846 $head2[$h][2] = 'specifications';
3847 $h++;
3848
3849 $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=buildpackage&module='.$module.($forceddirread ? '@'.$dirread : '');
3850 $head2[$h][1] = $langs->trans("BuildPackage");
3851 $head2[$h][2] = 'buildpackage';
3852 $h++;
3853
3854 $MAXTABFOROBJECT = 12;
3855
3856 print '<!-- Section for a given module -->';
3857
3858 // Note module is inside $dirread
3859
3860 if ($tab == 'description') {
3861 print '<!-- tab=description -->'."\n";
3862 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3863 $pathtofilereadme = $modulelowercase.'/README.md';
3864 $pathtochangelog = $modulelowercase.'/ChangeLog.md';
3865 $pathtoindex = $modulelowercase.'/'.$modulelowercase.'index.php';
3866
3867 $realpathofmodule = realpath($dirread.'/'.$modulelowercase);
3868
3869 if ($action != 'editfile' || empty($file)) {
3870 $morehtmlright = '';
3871 if ($realpathofmodule != $dirread.'/'.$modulelowercase) {
3872 $morehtmlright = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', '<span class="opacitymedium">'.$langs->trans("RealPathOfModule").' :</span> <strong class="wordbreak">'.$realpathofmodule.'</strong>').'</div>';
3873 }
3874
3875 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, $morehtmlright, '', $MAXTABFOROBJECT, 'formodulesuffix'); // Description - level 2
3876
3877 print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc".$tab).'</span>';
3878 print '<br><br>';
3879
3880 print '<table>';
3881
3882 print '<tr><td>';
3883 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3884 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>';
3885 print '</td></tr>';
3886
3887 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("Index").' : <strong class="wordbreak">'.$pathtoindex.'</strong>';
3888 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($pathtoindex).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
3889 print '</td></tr>';
3890
3891 // List of setup pages
3892 $listofsetuppages = dol_dir_list($realpathofmodule.'/admin', 'files', 0, '\.php$');
3893 foreach ($listofsetuppages as $setuppage) {
3894 // If this is a page for extrafields setup of an object
3895 $reg = array();
3896 if (preg_match('/^([a-z]+)_extrafields.php/', $setuppage['relativename'], $reg)) {
3897 // Check that object has $isextrafieldmanaged property set. If not, we should not show this file.
3898 $fileofclass = $realpathofmodule.'/class/'.$reg[1].'.class.php';
3899 if (is_readable($fileofclass) && !preg_match('/public\s+\$isextrafieldmanaged\s+=\s+1/', file_get_contents($fileofclass))) {
3900 continue;
3901 }
3902 }
3903
3904 //var_dump($setuppage);
3905 print '<tr><td>';
3906 print '<span class="fa fa-file"></span> ';
3907 if ($setuppage['relativename'] == 'about.php') {
3908 print $langs->trans("AboutFile");
3909 } else {
3910 print $langs->trans("SetupFile");
3911 }
3912 print ' : ';
3913 print '<strong class="wordbreak bold"><a href="'.dol_buildpath($modulelowercase.'/admin/'.$setuppage['relativename'], 1).'" target="_test">'.$modulelowercase.'/admin/'.$setuppage['relativename'].'</a></strong>';
3914 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>';
3915 print '</td></tr>';
3916 }
3917
3918 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("ReadmeFile").' : <strong class="wordbreak">'.$pathtofilereadme.'</strong>';
3919 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>';
3920 print '</td></tr>';
3921
3922 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("ChangeLog").' : <strong class="wordbreak">'.$pathtochangelog.'</strong>';
3923 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>';
3924 print '</td></tr>';
3925
3926 print '</table>';
3927 print '<br>';
3928
3929 print load_fiche_titre($form->textwithpicto($langs->trans("DescriptorFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofile), '', '');
3930
3931 if (is_object($moduleobj)) {
3932 print '<div class="underbanner clearboth"></div>';
3933 print '<div class="fichecenter">';
3934 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3935 print '<input type="hidden" name="token" value="'.newToken().'">';
3936 print '<input type="hidden" name="action" value="update_props_module">';
3937 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3938 print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
3939 print '<input type="hidden" name="keydescription" value="'.dol_escape_htmltag(GETPOST('keydescription', 'alpha')).'">';
3940
3941 print '<div class="div-table-responsive-no-min">';
3942 print '<table class="border centpercent">';
3943 print '<tr class="liste_titre"><td class="titlefield">';
3944 print $langs->trans("Parameter");
3945 print '</td><td>';
3946 print $langs->trans("Value");
3947 print '</td></tr>';
3948
3949 print '<tr><td>';
3950 print $langs->trans("IdModule");
3951 print '</td><td>';
3952 print $moduleobj->numero;
3953 print '<span class="opacitymedium">';
3954 print ' &nbsp; (';
3955 print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
3956 print ' - <a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>)';
3957 print '</span>';
3958 print '</td></tr>';
3959
3960 print '<tr><td>';
3961 print $langs->trans("ModuleName");
3962 print '</td><td>';
3963 print $moduleobj->getName();
3964 print '</td></tr>';
3965
3966 print '<tr><td>';
3967 print $langs->trans("Description");
3968 print '</td><td>';
3969 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'desc') {
3970 print '<input class="minwidth500" name="propsmodule" value="'.dol_escape_htmltag($moduleobj->description).'" spellcheck="false">';
3971 print '<input class="reposition button smallpaddingimp" type="submit" name="modifydesc" value="'.$langs->trans("Modify").'"/>';
3972 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3973 } else {
3974 print $moduleobj->description;
3975 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>';
3976
3977 $moduledescritpionautotrans = $moduleobj->getDesc();
3978 if ($moduledescritpionautotrans != "Module".$moduleobj->name."Desc") {
3979 // $moduledescritpionautotrans has been found into a translation file
3980 print ' '.$form->textwithpicto('', $langs->trans("ModuleTranslatedIntoLangForKeyInto", "Module".$moduleobj->name."Desc", $moduledescritpionautotrans));
3981 } elseif ($moduledescritpionautotrans != "Module".$moduleobj->numero."Desc") {
3982 // $moduledescritpionautotrans has been found into a translation file
3983 print ' '.$form->textwithpicto('', $langs->trans("ModuleTranslatedIntoLangForKeyInto", "Module".$moduleobj->numero."Desc", $moduledescritpionautotrans));
3984 }
3985 }
3986 print '</td></tr>';
3987
3988 print '<tr><td>';
3989 print $langs->trans("Version");
3990 print '</td><td>';
3991 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'version') {
3992 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->getVersion()).'">';
3993 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyversion" value="'.$langs->trans("Modify").'"/>';
3994 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
3995 } else {
3996 print $moduleobj->getVersion();
3997 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>';
3998 }
3999 print '</td></tr>';
4000
4001 print '<tr><td>';
4002 print $langs->trans("Family");
4003 //print "<br>'crm','financial','hr','projects','products','ecm','technic','interface','other'";
4004 print '</td><td>';
4005 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'family') {
4006 print '<select name="propsmodule" id="family" class="minwidth400">';
4007 $arrayoffamilies = array(
4008 'hr' => "ModuleFamilyHr",
4009 'crm' => "ModuleFamilyCrm",
4010 'srm' => "ModuleFamilySrm",
4011 'financial' => 'ModuleFamilyFinancial',
4012 'products' => 'ModuleFamilyProducts',
4013 'projects' => 'ModuleFamilyProjects',
4014 'ecm' => 'ModuleFamilyECM',
4015 'technic' => 'ModuleFamilyTechnic',
4016 'portal' => 'ModuleFamilyPortal',
4017 'interface' => 'ModuleFamilyInterface',
4018 'base' => 'ModuleFamilyBase',
4019 'other' => 'ModuleFamilyOther'
4020 );
4021 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>';
4022 foreach ($arrayoffamilies as $key => $value) {
4023 if ($key != $moduleobj->family) {
4024 print '<option value="'.$key.'" data-html="'.dol_escape_htmltag($langs->trans($value).' <span class="opacitymedium">- '.$key.'</span>').'">'.$langs->trans($value).'</option>';
4025 }
4026 }
4027 print '</select>';
4028 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyfamily" value="'.$langs->trans("Modify").'"/>';
4029 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
4030 } else {
4031 print $moduleobj->family;
4032 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>';
4033 }
4034 print '</td></tr>';
4035
4036 print '<!-- picto of module -->'."\n";
4037 print '<tr><td>';
4038 print $langs->trans("Picto");
4039 print '</td><td>';
4040 if ($action == 'edit_modulepicto' && GETPOST('keydescription', 'alpha') === 'picto') {
4041 print '<input class="minwidth200 maxwidth500" name="propsmodule" value="'.dol_escape_htmltag($moduleobj->picto).'" spellcheck="false">';
4042
4043 print $form->textwithpicto('', $langs->trans("Example").': fa-file, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]] where faprefix can be far,far, facolor can be a text like \'red\' orvalue like \'#FF0000\' and fasize is CSS font size like \'1em\'');
4044
4045 print '<input class="reposition button smallpaddingimp" type="submit" name="modifypicto" value="'.$langs->trans("Modify").'"/>';
4046 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
4047
4048 print ' &nbsp; &nbsp; ';
4049
4050 print '<span class="opacitymedium small">';
4051 print dolButtonToOpenUrlInDialogPopup('popup_picto_id', $langs->transnoentitiesnoconv("DocIconsList"), $langs->transnoentitiesnoconv("DocIconsList"), '/admin/tools/ui/components/icons.php?hidenavmenu=1&displayMode=icon-only&mode=no-btn#img-picto-section-list', '', '');
4052 print '</span>';
4053 } else {
4054 print $moduleobj->picto;
4055 print ' &nbsp; '.img_picto('', $moduleobj->picto, 'class="valignmiddle pictomodule paddingrightonly"');
4056 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>';
4057 }
4058 print '</td></tr>';
4059
4060 print '<tr><td>';
4061 print $langs->trans("EditorName");
4062 print '</td><td>';
4063 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'editor_name') {
4064 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->editor_name).'" spellcheck="false">';
4065 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyname" value="'.$langs->trans("Modify").'"/>';
4066 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
4067 } else {
4068 print $moduleobj->editor_name;
4069 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>';
4070 }
4071 print '</td></tr>';
4072
4073 print '<tr><td>';
4074 print $langs->trans("EditorUrl");
4075 print '</td><td>';
4076 if ($action == 'edit_moduledescription' && GETPOST('keydescription', 'alpha') === 'editor_url') {
4077 print '<input name="propsmodule" value="'.dol_escape_htmltag($moduleobj->editor_url).'" spellcheck="false">';
4078 print '<input class="reposition button smallpaddingimp" type="submit" name="modifyeditorurl" value="'.$langs->trans("Modify").'"/>';
4079 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
4080 } else {
4081 if (!empty($moduleobj->editor_url)) {
4082 print '<a href="'.$moduleobj->editor_url.'" target="_blank" rel="noopener">'.$moduleobj->editor_url.' '.img_picto('', 'globe').'</a>';
4083 }
4084 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>';
4085 }
4086 print '</td></tr>';
4087
4088 print '</table>';
4089 print '</div>';
4090 print '</form>';
4091 } else {
4092 print $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
4093 }
4094
4095 if (!empty($moduleobj)) {
4096 print '<br><br>';
4097
4098 // Readme file
4099 print load_fiche_titre($form->textwithpicto($langs->trans("ReadmeFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofilereadme), '', '');
4100
4101 print '<!-- readme file -->';
4102 if (dol_is_file($dirread.'/'.$pathtofilereadme)) {
4103 print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getDescLong().'</div>';
4104 } else {
4105 print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtofilereadme).'</span>';
4106 }
4107
4108 print '<br><br>';
4109
4110 // ChangeLog
4111 print load_fiche_titre($form->textwithpicto($langs->trans("ChangeLog"), $langs->transnoentitiesnoconv("File").' '.$pathtochangelog), '', '');
4112
4113 print '<!-- changelog file -->';
4114 if (dol_is_file($dirread.'/'.$pathtochangelog)) {
4115 print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getChangeLog().'</div>';
4116 } else {
4117 print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtochangelog).'</span>';
4118 }
4119 }
4120
4121 print dol_get_fiche_end();
4122 } else { // Edit text file
4123 $fullpathoffile = dol_buildpath($file, 0, 1); // Description - level 2
4124
4125 $content = '';
4126 if ($fullpathoffile) {
4127 $content = file_get_contents($fullpathoffile);
4128 }
4129
4130 // New module
4131 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4132 print '<input type="hidden" name="token" value="'.newToken().'">';
4133 print '<input type="hidden" name="action" value="savefile">';
4134 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4135 print '<input type="hidden" name="tab" value="'.$tab.'">';
4136 print '<input type="hidden" name="module" value="'.$module.'">';
4137
4138 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', 0, 'formodulesuffix');
4139
4140 $posCursor = (empty($find)) ? array() : array('find' => $find);
4141 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
4142 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
4143
4144 print dol_get_fiche_end();
4145
4146 print '<center>';
4147 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4148 print ' &nbsp; ';
4149 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4150 print '</center>';
4151
4152 print '</form>';
4153 }
4154 } else {
4155 print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', $MAXTABFOROBJECT, 'formodulesuffix'); // Level 2
4156 }
4157
4158 if ($tab == 'languages') {
4159 print '<!-- tab=languages -->'."\n";
4160 if ($action != 'editfile' || empty($file)) {
4161 print '<span class="opacitymedium">'.$langs->trans("LanguageDefDesc").'</span><br>';
4162 print '<br>';
4163
4164
4165 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4166 print '<input type="hidden" name="token" value="'.newToken().'">';
4167 print '<input type="hidden" name="action" value="addlanguage">';
4168 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4169 print '<input type="hidden" name="tab" value="'.$tab.'">';
4170 print '<input type="hidden" name="module" value="'.$module.'">';
4171 print $formadmin->select_language(getDolGlobalString('MAIN_LANG_DEFAULT'), 'newlangcode', 0, array(), 1, 0, 0, 'minwidth300', 1);
4172 print '<input type="submit" name="addlanguage" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("AddLanguageFile")).'"><br>';
4173 print '</form>';
4174
4175 print '<br>';
4176 print '<br>';
4177
4178 $modulelowercase = strtolower($module);
4179
4180 // Dir for module
4181 $diroflang = dol_buildpath($modulelowercase, 0);
4182 $diroflang .= '/langs';
4183 $langfiles = dol_dir_list($diroflang, 'files', 1, '\.lang$');
4184
4185 if (!preg_match('/custom/', $dirread)) {
4186 // If this is not a module into custom
4187 $diroflang = $dirread;
4188 $diroflang .= '/langs';
4189 $langfiles = dol_dir_list($diroflang, 'files', 1, $modulelowercase.'\.lang$');
4190 }
4191
4192 print '<table class="none">';
4193 foreach ($langfiles as $langfile) {
4194 $pathtofile = $modulelowercase.'/langs/'.$langfile['relativename'];
4195 if (!preg_match('/custom/', $dirread)) { // If this is not a module into custom
4196 $pathtofile = 'langs/'.$langfile['relativename'];
4197 }
4198 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("LanguageFile").' '.basename(dirname($pathtofile)).' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4199 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>';
4200 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>';
4201 print '</td>';
4202 }
4203 print '</table>';
4204 } else {
4205 // Edit text language file
4206
4207 //print $langs->trans("UseAsciiDocFormat").'<br>';
4208
4209 $fullpathoffile = dol_buildpath($file, 0);
4210
4211 $content = file_get_contents($fullpathoffile);
4212
4213 // New module
4214 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4215 print '<input type="hidden" name="token" value="'.newToken().'">';
4216 print '<input type="hidden" name="action" value="savefile">';
4217 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4218 print '<input type="hidden" name="tab" value="'.$tab.'">';
4219 print '<input type="hidden" name="module" value="'.$module.'">';
4220
4221 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
4222 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'text'));
4223 print '<br>';
4224 print '<center>';
4225 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4226 print ' &nbsp; ';
4227 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4228 print '</center>';
4229
4230 print '</form>';
4231 }
4232 }
4233
4234 if ($tab == 'objects') {
4235 print '<!-- tab=objects -->'."\n";
4236 $head3 = array();
4237 $h = 0;
4238
4239 // Dir for module
4240 $dir = $dirread.'/'.$modulelowercase.'/class';
4241
4242 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=newobject';
4243 $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewObjectInModulebuilder").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
4244 $head3[$h][2] = 'newobject';
4245 $h++;
4246
4247 // Scan for object class files
4248 $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
4249
4250 $firstobjectname = '';
4251 foreach ($listofobject as $fileobj) {
4252 if (preg_match('/^api_/', $fileobj['name'])) {
4253 continue;
4254 }
4255 if (preg_match('/^actions_/', $fileobj['name'])) {
4256 continue;
4257 }
4258
4259 $tmpcontent = file_get_contents($fileobj['fullname']);
4260 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
4261 //$objectname = preg_replace('/\.txt$/', '', $fileobj['name']);
4262 $objectname = $reg[1];
4263 if (empty($firstobjectname)) {
4264 $firstobjectname = $objectname;
4265 }
4266 $pictoname = 'generic';
4267 if (preg_match('/\$picto\s*=\s*["\']([^"\']+)["\']/', $tmpcontent, $reg)) {
4268 $pictoname = $reg[1];
4269 }
4270
4271 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname;
4272 $head3[$h][1] = img_picto('', $pictoname, 'class="pictofixedwidth valignmiddle"').$objectname;
4273 $head3[$h][2] = $objectname;
4274 $h++;
4275 }
4276 }
4277
4278 if ($h > 1) {
4279 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=deleteobject';
4280 $head3[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
4281 $head3[$h][2] = 'deleteobject';
4282 $h++;
4283 }
4284
4285 // 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.
4286 if ($tabobj == 'newobjectifnoobj') {
4287 if ($firstobjectname) {
4288 $tabobj = $firstobjectname;
4289 } else {
4290 $tabobj = 'newobject';
4291 }
4292 }
4293
4294 print dol_get_fiche_head($head3, $tabobj, '', -1, '', 0, '', '', 0, 'forobjectsuffix'); // Level 3
4295
4296
4297 if ($tabobj == 'newobject') {
4298 // New object tab
4299 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4300 print '<input type="hidden" name="token" value="'.newToken().'">';
4301 print '<input type="hidden" name="action" value="initobject">';
4302 print '<input type="hidden" name="tab" value="objects">';
4303 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4304
4305 // Tabs selected by default = all optional tabs; reflect posted state on redisplay
4306 $enabledtabsdefault = GETPOSTISSET('enabledtab') ? GETPOST('enabledtab', 'array') : array_keys(getModuleBuilderObjectTabs());
4307
4308 print '<span class="opacitymedium">'.$langs->trans("EnterNameOfObjectDesc").'</span><br><br>';
4309
4310 print '<div class="tagtable">';
4311
4312 print '<div class="tagtr"><div class="tagtd">';
4313 print '<span class="opacitymedium">'.$langs->trans("ObjectKey").'</span> &nbsp; ';
4314 print '</div><div class="tagtd">';
4315 print '<input type="text" name="objectname" maxlength="64" value="'.dol_escape_htmltag(GETPOSTISSET('objectname') ? GETPOST('objectname', 'alpha') : $modulename).'" required autofocus>';
4316 print $form->textwithpicto('', $langs->trans("Example").': MyObject, ACamelCaseName, ...');
4317 print '</div></div>';
4318
4319 print '<div class="tagtr"><div class="tagtd">';
4320 print '<span class="opacitymedium">'.$langs->trans("Picto").'</span> &nbsp; ';
4321 print '</div><div class="tagtd">';
4322 print '<input type="text" name="idpicto" value="fa-file" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
4323
4324 print $form->textwithpicto('', $langs->trans("Example").': fa-file, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]] where faprefix can be far,far, facolor can be a text like \'red\' orvalue like \'#FF0000\' and fasize is CSS font size like \'1em\'');
4325
4326 print '<span class="opacitymedium small">';
4327 print ' &nbsp; &nbsp; ';
4328 print dolButtonToOpenUrlInDialogPopup('popup_picto_id', $langs->transnoentitiesnoconv("DocIconsList"), $langs->transnoentitiesnoconv("DocIconsList"), '/admin/tools/ui/components/icons.php?hidenavmenu=1&displayMode=icon-only&mode=no-btn#img-picto-section-list', '', '');
4329 print '</span>';
4330
4331 print '</div></div>';
4332
4333 print '<div class="tagtr"><div class="tagtd">';
4334 print '<span class="opacitymedium">'.$langs->trans("DefinePropertiesFromExistingTable").'</span> &nbsp; ';
4335 print '</div><div class="tagtd">';
4336 print '<input type="text" name="initfromtablename" value="'.GETPOST('initfromtablename').'" placeholder="'.$langs->trans("TableName").'">';
4337 print $form->textwithpicto('', $langs->trans("DefinePropertiesFromExistingTableDesc").'<br>'.$langs->trans("DefinePropertiesFromExistingTableDesc2"));
4338 print '</div></div>';
4339
4340 print '</div>';
4341
4342 print '<br>';
4343 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>';
4344 print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
4345 print '<input type="checkbox" name="generatepermissions" id="generatepermissions" value="generatepermissions"> <label for="generatepermissions">'.$form->textwithpicto($langs->trans("GeneratePermissions"), $langs->trans("GeneratePermissionsHelp")).'</label><br>';
4346 print '<input type="checkbox" name="nogeneratelines" id="nogeneratelines" value="nogeneratelines"> <label for="nogeneratelines">'.$form->textwithpicto($langs->trans("NoGenerateLines"), $langs->trans("NoGenerateLinesHelp")).'</label><br>';
4347 print '<br><span class="opacitymedium">'.$form->textwithpicto($langs->trans("EnabledTabsForObject"), $langs->trans("EnabledTabsForObjectHelp")).'</span><br>';
4348 foreach (getModuleBuilderObjectTabs() as $tabkey => $tabinfo) {
4349 $checked = in_array($tabkey, $enabledtabsdefault, true) ? ' checked' : '';
4350 print '<input type="checkbox" name="enabledtab[]" id="enabledtab_'.$tabkey.'" value="'.dol_escape_htmltag($tabkey).'"'.$checked.'> ';
4351 print '<label for="enabledtab_'.$tabkey.'">'.dol_escape_htmltag($langs->trans($tabinfo['label'])).'</label> &nbsp; ';
4352 }
4353 print '<br>';
4354 print '<br>';
4355 print '<input type="submit" class="button small" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4356 print '<br>';
4357 print '<br>';
4358 /*
4359 print '<br>';
4360 print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
4361 print '<br>';
4362 print '<br>';
4363 //print '<input type="checkbox" name="initfromtablecheck"> ';
4364 print $langs->trans("InitStructureFromExistingTable");
4365 print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
4366 print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4367 print '<br>';
4368 */
4369
4370 print '</form>';
4371 } elseif ($tabobj == 'createproperty') {
4372 $attributesUnique = array(
4373 'proplabel' => $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey")),
4374 'propname' => $form->textwithpicto($langs->trans("Code"), $langs->trans("PropertyDesc"), 1, 'help', 'extracss', 0, 3, 'propertyhelp'),
4375 'proptype' => $form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp'),
4376 'proparrayofkeyval' => $form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")),
4377 'propnotnull' => $form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")),
4378 'propdefault' => $langs->trans("DefaultValue"),
4379 'propindex' => $langs->trans("DatabaseIndex"),
4380 'propforeignkey' => $form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp'),
4381 'propposition' => $langs->trans("Position"),
4382 'propenabled' => $form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp'),
4383 'propvisible' => $form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp'),
4384 'propnoteditable' => $langs->trans("NotEditable"),
4385 //'propalwayseditable' => $langs->trans("AlwaysEditable"),
4386 'propsearchall' => $form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")),
4387 'propisameasure' => $form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")),
4388 'propcss' => $langs->trans("CSSClass"),
4389 'propcssview' => $langs->trans("CSSViewClass"),
4390 'propcsslist' => $langs->trans("CSSListClass"),
4391 'prophelp' => $langs->trans("KeyForTooltip"),
4392 'propshowoncombobox' => $langs->trans("ShowOnCombobox"),
4393 //'propvalidate' => $form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")),
4394 'propcomment' => $langs->trans("Comment"),
4395 );
4396 print '<form action="'.$_SERVER["PHP_SELF"].'?tab=objects&module='.urlencode($module).'&tabobj=createproperty&obj='.urlencode(GETPOST('obj')).'" method="POST">';
4397 print '<input type="hidden" name="token" value="'.newToken().'">';
4398 print '<input type="hidden" name="action" value="addproperty">';
4399 print '<input type="hidden" name="tab" value="objects">';
4400 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4401 print '<input type="hidden" name="obj" value="'.dol_escape_htmltag(GETPOST('obj')).'">';
4402
4403 print '<table class="border centpercent tableforfieldcreate">'."\n";
4404 $counter = 0;
4405 foreach ($attributesUnique as $key => $attribute) {
4406 if ($counter % 2 === 0) {
4407 print '<tr>';
4408 }
4409 if ($key == 'propname' || $key == 'proplabel') {
4410 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>';
4411 } elseif ($key == 'proptype') {
4412 print '<td class="titlefieldcreate fieldrequired">'.$attribute.'</td><td class="valuefieldcreate maxwidth50">';
4413 print '<input class="maxwidth200" name="'.$key.'" id="'.$key.'" list="datalist'.$key.'" type="text" value="'.dol_escape_htmltag(GETPOST($key, 'alpha')).'">';
4414 //print '<div id="suggestions"></div>';
4415 print '<datalist id="datalist'.$key.'">';
4416 print '<option>varchar(128)</option>';
4417 print '<option>email</option>';
4418 print '<option>phone</option>';
4419 print '<option>ip</option>';
4420 print '<option>url</option>';
4421 print '<option>password</option>';
4422 print '<option>text</option>';
4423 print '<option>html</option>';
4424 print '<option>date</option>';
4425 print '<option>datetime</option>';
4426 print '<option>integer</option>';
4427 print '<option>stars(5)</option>';
4428 print '<option>double(28,4)</option>';
4429 print '<option>real</option>';
4430 print '<option>integer:ClassName:RelativePath/To/ClassFile.class.php[:1[:FILTER]]</option>';
4431 // Combo with list of fields
4432 /*
4433 if (empty($formadmin)) {
4434 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
4435 $formadmin = new FormAdmin($db);
4436 }
4437 print $formadmin->selectTypeOfFields($key, GETPOST($key, 'alpha'));
4438 */
4439 print '</datalist>';
4440 print '</td>';
4441 //} elseif ($key == 'propvalidate') {
4442 // 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>';
4443 } elseif ($key == 'propvisible') {
4444 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>';
4445 } elseif ($key == 'propenabled') {
4446 //$default = "isModEnabled('".strtolower($module)."')";
4447 $default = 1;
4448 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>';
4449 } elseif ($key == 'proparrayofkeyval') {
4450 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>';
4451 } else {
4452 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>';
4453 }
4454 $counter++;
4455 if ($counter % 2 === 0) {
4456 print '</tr>';
4457 }
4458 }
4459 if ($counter % 2 !== 0) {
4460 while ($counter % 2 !== 0) {
4461 print '<td></td>';
4462 $counter++;
4463 }
4464 print '</tr>';
4465 }
4466 print '</table><br>'."\n";
4467 print '<div class="center">';
4468 print '<input type="submit" class="button button-save" name="add" value="' . dol_escape_htmltag($langs->trans('Create')) . '">';
4469 print '<input type="button" class="button button-cancel" name="cancel" value="' . dol_escape_htmltag($langs->trans('Cancel')) . '" onclick="goBack()">';
4470 print '</div>';
4471 print '</form>';
4472 // javascript
4473 print '<script>
4474 function goBack() {
4475 var url = "'.$_SERVER["PHP_SELF"].'?tab=objects&module='.urlencode($module).'";
4476 window.location.href = url;
4477 }
4478 $(document).ready(function() {
4479 $("#proplabel").on("keyup", function() {
4480 console.log("key up on label");
4481 s = cleanString($("#proplabel").val());
4482 $("#propname").val(s);
4483 });
4484
4485 function cleanString( stringtoclean )
4486 {
4487 // allow "a-z", "A-Z", "0-9" and "_"
4488 stringtoclean = stringtoclean.replace(/[^a-z0-9_]+/ig, "");
4489 stringtoclean = stringtoclean.toLowerCase();
4490 if (!isNaN(stringtoclean)) {
4491 return ""
4492 }
4493 while ( stringtoclean.length > 1 && !isNaN( stringtoclean.charAt(0)) ){
4494 stringtoclean = stringtoclean.substr(1)
4495 }
4496 if (stringtoclean.length > 28) {
4497 stringtoclean = stringtoclean.substring(0, 27);
4498 }
4499 return stringtoclean;
4500 }
4501
4502 });';
4503 print '</script>';
4504 } elseif ($tabobj == 'deleteobject') {
4505 // Delete object tab
4506 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4507 print '<input type="hidden" name="token" value="'.newToken().'">';
4508 print '<input type="hidden" name="action" value="confirm_deleteobject">';
4509 print '<input type="hidden" name="tab" value="objects">';
4510 print '<input type="hidden" name="tabobj" value="deleteobject">';
4511 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4512
4513 print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
4514
4515 print '<input type="text" class="valignmiddle" name="objectname" value="" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'" autofocus>';
4516 print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4517 print '</form>';
4518 } else {
4519 // tabobj = module
4520 if ($action == 'deleteproperty') {
4521 $formconfirm = $form->formconfirm(
4522 $_SERVER["PHP_SELF"].'?propertykey='.urlencode(GETPOST('propertykey', 'alpha')).'&objectname='.urlencode($objectname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj),
4523 $langs->trans('Delete'),
4524 $langs->trans('ConfirmDeleteProperty', GETPOST('propertykey', 'alpha')),
4525 'confirm_deleteproperty',
4526 '',
4527 0,
4528 1
4529 );
4530
4531 // Print form confirm
4532 print $formconfirm;
4533 }
4534 if ($action != 'editfile' || empty($file)) {
4535 try {
4536 //$pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4537
4538 $pathtoclass = strtolower($module).'/class/'.strtolower($tabobj).'.class.php';
4539 $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'.class.php';
4540 $pathtoagenda = strtolower($module).'/'.strtolower($tabobj).'_agenda.php';
4541 $pathtocard = strtolower($module).'/'.strtolower($tabobj).'_card.php';
4542 $pathtodocument = strtolower($module).'/'.strtolower($tabobj).'_document.php';
4543 $pathtolist = strtolower($module).'/'.strtolower($tabobj).'_list.php';
4544 $pathtonote = strtolower($module).'/'.strtolower($tabobj).'_note.php';
4545 $pathtocontact = strtolower($module).'/'.strtolower($tabobj).'_contact.php';
4546 $pathtophpunit = strtolower($module).'/test/phpunit/'.strtolower($tabobj).'Test.php';
4547
4548 // Try to load object class file
4549 clearstatcache(true);
4550 if (function_exists('opcache_invalidate')) {
4551 opcache_invalidate($dirread.'/'.$pathtoclass, true); // remove the include cache hell !
4552 }
4553
4554 if (empty($forceddirread) && empty($dirread)) {
4555 $result = dol_include_once($pathtoclass);
4556 $stringofinclude = "dol_include_once(".$pathtoclass.")";
4557 } else {
4558 $result = include_once $dirread.'/'.$pathtoclass;
4559 $stringofinclude = "@include_once ".$dirread.'/'.$pathtoclass;
4560 }
4561
4562 if (class_exists($tabobj)) {
4563 try {
4564 $tmpobject = @new $tabobj($db);
4565 } catch (Exception $e) {
4566 dol_syslog('Failed to load Constructor of class: '.$e->getMessage(), LOG_WARNING);
4567 }
4568 } else {
4569 print '<span class="warning">'.$langs->trans('Failed to find the class '.$tabobj.' despite the '.$stringofinclude).'</span><br><br>';
4570 }
4571
4572 // Define path for sql file
4573 $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
4574 $result = dol_buildpath($pathtosql);
4575 if (! dol_is_file($result)) {
4576 $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'.sql';
4577 $result = dol_buildpath($pathtosql);
4578 if (! dol_is_file($result)) {
4579 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
4580 $result = dol_buildpath($pathtosql);
4581 if (! dol_is_file($result)) {
4582 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
4583 $result = dol_buildpath($pathtosql);
4584 if (! dol_is_file($result)) {
4585 $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'.sql';
4586 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields.sql';
4587 $result = dol_buildpath($pathtosql);
4588 } else {
4589 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields-'.strtolower($module).'.sql';
4590 }
4591 } else {
4592 $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
4593 }
4594 } else {
4595 $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields.sql';
4596 }
4597 } else {
4598 $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
4599 }
4600 $pathtosqlroot = preg_replace('/\/llx_.*$/', '', $pathtosql);
4601
4602 $pathtosqlkey = preg_replace('/\.sql$/', '.key.sql', $pathtosql);
4603 $pathtosqlextrakey = preg_replace('/\.sql$/', '.key.sql', $pathtosqlextra);
4604
4605 $pathtolib = strtolower($module).'/lib/'.strtolower($module).'.lib.php';
4606 $pathtoobjlib = strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($tabobj).'.lib.php';
4607
4608 $tmpobject = $tmpobject ?? null; // @phan-suppress-current-line PhanPluginDuplicateExpressionAssignmentOperation
4609 if (is_object($tmpobject) && property_exists($tmpobject, 'picto')) {
4610 $pathtopicto = $tmpobject->picto;
4611 $realpathtopicto = '';
4612 } else {
4613 $pathtopicto = strtolower($module).'/img/object_'.strtolower($tabobj).'.png';
4614 $realpathtopicto = $dirread.'/'.$pathtopicto;
4615 }
4616
4617 //var_dump($pathtoclass);
4618 //var_dump($dirread);
4619 $realpathtoclass = $dirread.'/'.$pathtoclass;
4620 $realpathtoapi = $dirread.'/'.$pathtoapi;
4621 $realpathtoagenda = $dirread.'/'.$pathtoagenda;
4622 $realpathtocard = $dirread.'/'.$pathtocard;
4623 $realpathtodocument = $dirread.'/'.$pathtodocument;
4624 $realpathtolist = $dirread.'/'.$pathtolist;
4625 $realpathtonote = $dirread.'/'.$pathtonote;
4626 $realpathtocontact = $dirread.'/'.$pathtocontact;
4627 $realpathtophpunit = $dirread.'/'.$pathtophpunit;
4628 $realpathtosql = $dirread.'/'.$pathtosql;
4629 $realpathtosqlextra = $dirread.'/'.$pathtosqlextra;
4630 $realpathtosqlkey = $dirread.'/'.$pathtosqlkey;
4631 $realpathtosqlextrakey = $dirread.'/'.$pathtosqlextrakey;
4632 $realpathtolib = $dirread.'/'.$pathtolib;
4633 $realpathtoobjlib = $dirread.'/'.$pathtoobjlib;
4634
4635 if (empty($realpathtoapi)) { // For compatibility with some old modules
4636 $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'s.class.php';
4637 $realpathtoapi = $dirread.'/'.$pathtoapi;
4638 }
4639
4640 $urloflist = dol_buildpath('/'.$pathtolist, 1);
4641 $urlofcard = dol_buildpath('/'.$pathtocard, 1);
4642
4643 $objs = array();
4644
4645 // Image
4646 $htmltooltip = '';
4647 if ($realpathtopicto && dol_is_file($realpathtopicto)) {
4648 $htmltooltip .= '<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>';
4649 $htmltooltip .= '<br>';
4650 } elseif (!empty($tmpobject)) {
4651 $htmltooltip .= '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : '.img_picto('', $tmpobject->picto, 'class="pictofixedwidth valignmiddle"').$tmpobject->picto;
4652 $htmltooltip .= '<br>';
4653 }
4654 $htmltooltip .= '<span class="fa fa-file-image-o"></span> '.$langs->trans("IsExtraFieldManaged").' : '.yn(empty($tmpobject->isextrafieldmanaged) ? 0 : 1, 1, 2);
4655 $htmltooltip .= '<br>';
4656 $htmltooltip .= '<span class="fa fa-file-image-o"></span> '.$langs->trans("IsMultiEntityManaged").' : '.yn(empty($tmpobject->ismultientitymanaged) ? 0 : 1, 1, 2);
4657 $htmltooltip .= '<br>';
4658
4659 print '<!-- section for object -->';
4660 print '<div class="fichehalfleft smallxxx">';
4661 // Main DAO class file
4662 print '<span class="fa fa-file"></span> '.$langs->trans("ClassFile").' : <strong>'.(dol_is_file($realpathtoclass) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtoclass).(dol_is_file($realpathtoclass) ? '' : '</strike>').'</strong>';
4663 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>';
4664 print $form->textwithpicto('', $htmltooltip, 1, 'help', 'valignmiddle', 1);
4665 print '<br>';
4666
4667 // API file
4668 print '<br>';
4669 print '<span class="fa fa-file"></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>';
4670 if (dol_is_file($realpathtoapi)) {
4671 $file = file_get_contents($realpathtoapi);
4672 if (preg_match('/var '.$tabobj.'\s+([^\s]*)\s/ims', $file, $objs)) {
4673 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>';
4674 print ' ';
4675 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>';
4676 print $form->textwithpicto('', $langs->trans("InfoForApiFile"), 1, 'warning');
4677 print ' &nbsp; ';
4678 // Comparing to null (phan considers $modulelowercase can be null here)
4679 if (!isModEnabled($modulelowercase)) { // If module is not activated
4680 print '<a href="#" class="classfortooltip" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled", $module).'"><strike>'.$langs->trans("ApiExplorer").'</strike></a>';
4681 } else {
4682 print '<a href="'.DOL_URL_ROOT.'/api/index.php/explorer/" target="apiexplorer">'.$langs->trans("ApiExplorer").'</a>';
4683 }
4684 } else {
4685 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>';
4686 }
4687 } else {
4688 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>';
4689 }
4690 // PHPUnit
4691 print '<br>';
4692 print '<span class="fa fa-file"></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>';
4693 if (dol_is_file($realpathtophpunit)) {
4694 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>';
4695 print ' ';
4696 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>';
4697 } else {
4698 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>';
4699 }
4700 print '<br>';
4701
4702 print '<br>';
4703
4704 print '<span class="fa fa-file"></span> '.$langs->trans("PageForLib").' : <strong class="wordbreak">'.(dol_is_file($realpathtolib) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtolib).(dol_is_file($realpathtolib) ? '' : '</strike>').'</strong>';
4705 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>';
4706 print '<br>';
4707 print '<span class="fa fa-file"></span> '.$langs->trans("PageForObjLib").' : <strong class="wordbreak">'.(dol_is_file($realpathtoobjlib) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtoobjlib).(dol_is_file($realpathtoobjlib) ? '' : '</strike>').'</strong>';
4708 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>';
4709 print '<br>';
4710
4711 print '<br>';
4712 print '<span class="fa fa-file"></span> '.$langs->trans("SqlFile").' : <strong class="wordbreak">'.(dol_is_file($realpathtosql) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtosql).(dol_is_file($realpathtosql) ? '' : '</strike>').'</strong>';
4713 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>';
4714 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>';
4715 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4716 print '<br>';
4717 print '<span class="fa fa-file"></span> '.$langs->trans("SqlFileKey").' : <strong class="wordbreak">'.(dol_is_file($realpathtosqlkey) ? '' : '<strike>').preg_replace('/^'.strtolower($module).'\//', '', $pathtosqlkey).(dol_is_file($realpathtosqlkey) ? '' : '</strike>').'</strong>';
4718 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>';
4719 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4720 print '<br>';
4721 if (!empty($tmpobject->isextrafieldmanaged)) {
4722 print '<span class="fa fa-file"></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>';
4723 if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
4724 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>';
4725 print ' ';
4726 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>';
4727 print ' &nbsp; ';
4728 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>';
4729 } else {
4730 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>';
4731 }
4732
4733 //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
4734 print '<br>';
4735 print '<span class="fa fa-file"></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>';
4736 if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
4737 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>';
4738 print ' ';
4739 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>';
4740 } else {
4741 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>';
4742 }
4743 print '<br>';
4744 }
4745 print '</div>';
4746
4747 print '<div class="fichehalfleft smallxxxx">';
4748 print '<span class="fa fa-file"></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>';
4749 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>';
4750 print '<br>';
4751 print '<span class="fa fa-file"></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>';
4752 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>';
4753 print '<br>';
4754 // Page contact
4755 print '<span class="fa fa-file"></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>';
4756 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>';
4757 if (dol_is_file($realpathtocontact)) {
4758 print ' ';
4759 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>';
4760 } else {
4761 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>';
4762 }
4763 print '<br>';
4764 // Page document
4765 print '<span class="fa fa-file"></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>';
4766 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>';
4767 if (dol_is_file($realpathtodocument)) {
4768 print ' ';
4769 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>';
4770 } else {
4771 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>';
4772 }
4773 print '<br>';
4774 // Page notes
4775 print '<span class="fa fa-file"></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>';
4776 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>';
4777 if (dol_is_file($realpathtonote)) {
4778 print ' ';
4779 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>';
4780 } else {
4781 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>';
4782 }
4783 print '<br>';
4784 // Page agenda
4785 print '<span class="fa fa-file"></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>';
4786 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>';
4787 if (dol_is_file($realpathtoagenda)) {
4788 print ' ';
4789 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>';
4790 } else {
4791 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>';
4792 }
4793 print '<br>';
4794 print '<br>';
4795
4796 print '</div>';
4797
4798 print '<br><br><br>';
4799
4800 if (!empty($tmpobject)) {
4801 $reflector = new ReflectionClass($tabobj);
4802 $reflectorproperties = $reflector->getProperties(); // Can also use get_object_vars
4803 $reflectorpropdefault = $reflector->getDefaultProperties(); // Can also use get_object_vars
4804 //$propstat = $reflector->getStaticProperties();
4805 //var_dump($reflectorpropdefault);
4806
4807 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4808 print '<input type="hidden" name="token" value="'.newToken().'">';
4809 print '<input type="hidden" name="action" value="addproperty">';
4810 print '<input type="hidden" name="tab" value="objects">';
4811 print '<input type="hidden" name="page_y" value="">';
4812 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module.($forceddirread ? '@'.$dirread : '')).'">';
4813 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4814
4815 print '<input class="button smallpaddingimp" type="submit" name="regenerateclasssql" value="'.$langs->trans("RegenerateClassAndSql").'">';
4816 print '<br><br class="clearboth">';
4817 print '<br class="clearboth">';
4818
4819 $mod = strtolower($module);
4820 $obj = strtolower($tabobj);
4821 $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));
4822 $nbOfProperties = count($reflectorpropdefault['fields']);
4823
4824 print_barre_liste($langs->trans("ObjectProperties"), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, $nbOfProperties, '', 0, $newproperty, 'margintoponly', 0, 0, 0, 1);
4825
4826 //var_dump($reflectorpropdefault);exit;
4827 print '<!-- Table with properties of object -->'."\n";
4828 print '<div class="div-table-responsive">';
4829 print '<table class="noborder small">';
4830 print '<tr class="liste_titre">';
4831 if (!empty($conf->main_checkbox_left_column)) {
4832 print '<th class="tdstickyright tdstickyghostwhite"></th>';
4833 }
4834 print '<th class="tdsticky tdstickygray">';
4835 $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>';
4836 print $form->textwithpicto($langs->trans("Code"), $htmltext, 1, 'help', 'extracss', 0, 3, 'propertyhelp');
4837 print '</th>';
4838 print '<th>';
4839 print $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey"));
4840 print '</th>';
4841 print '<th>'.$form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp').'</th>';
4842 print '<th>'.$form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")).'</th>';
4843 print '<th class="center">'.$form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")).'</th>';
4844 print '<th class="center">'.$langs->trans("DefaultValue").'</th>';
4845 print '<th class="center">'.$langs->trans("DatabaseIndex").'</th>';
4846 print '<th class="center">'.$form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp').'</th>';
4847 print '<th class="right">'.$langs->trans("Position").'</th>';
4848 print '<th class="center">'.$form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp').'</th>';
4849 print '<th class="center">'.$form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp').'</th>';
4850 print '<th class="center">'.$langs->trans("NotEditable").'</th>';
4851 //print '<th class="center">'.$langs->trans("AlwaysEditable").'</th>';
4852 print '<th class="center">'.$form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")).'</th>';
4853 print '<th class="center">'.$form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")).'</th>';
4854 print '<th class="center">'.$langs->trans("CSSClass").'</th>';
4855 print '<th class="center">'.$langs->trans("CSSViewClass").'</th>';
4856 print '<th class="center">'.$langs->trans("CSSListClass").'</th>';
4857 print '<th>'.$langs->trans("KeyForTooltip").'</th>';
4858 print '<th class="center">'.$langs->trans("ShowOnCombobox").'</th>';
4859 //print '<th class="center">'.$langs->trans("Disabled").'</th>';
4860 print '<th>'.$form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")).'</th>';
4861 print '<th>'.$langs->trans("Comment").'</th>';
4862 if (empty($conf->main_checkbox_left_column)) {
4863 print '<th class="tdstickyright tdstickyghostwhite"></th>';
4864 }
4865 print '</tr>';
4866
4867 // We must use $reflectorpropdefault['fields'] to get list of fields because $tmpobject->fields may have been
4868 // modified during the constructor and we want value into head of class before constructor is called.
4869 //$properties = dol_sort_array($tmpobject->fields, 'position');
4870 $properties = dol_sort_array($reflectorpropdefault['fields'], 'position');
4871 if (!empty($properties)) {
4872 // List of existing properties
4873 foreach ($properties as $propkey => $propval) {
4874 /* If from Reflection
4875 if ($propval->class == $tabobj)
4876 {
4877 $propname=$propval->getName();
4878 $comment=$propval->getDocComment();
4879 $type=gettype($tmpobject->$propname);
4880 $default=$propdefault[$propname];
4881 // Discard generic properties
4882 if (in_array($propname, array('element', 'childtables', 'table_element', 'table_element_line', 'class_element_line', 'ismultientitymanaged'))) continue;
4883
4884 // Keep or not lines
4885 if (in_array($propname, array('fk_element', 'lines'))) continue;
4886 }*/
4887
4888 $propname = $propkey;
4889 $proplabel = $propval['label'];
4890 $proptype = $propval['type'];
4891 $proparrayofkeyval = !empty($propval['arrayofkeyval']) ? $propval['arrayofkeyval'] : '';
4892 $propnotnull = !empty($propval['notnull']) ? $propval['notnull'] : '0';
4893 $propdefault = !empty($propval['default']) ? $propval['default'] : '';
4894 $propindex = !empty($propval['index']) ? $propval['index'] : '';
4895 $propforeignkey = !empty($propval['foreignkey']) ? $propval['foreignkey'] : '';
4896 $propposition = $propval['position'];
4897 $propenabled = $propval['enabled'];
4898 $propvisible = $propval['visible'];
4899 $propnoteditable = !empty($propval['noteditable']) ? $propval['noteditable'] : 0;
4900 //$propalwayseditable = !empty($propval['alwayseditable'])?$propval['alwayseditable']:0;
4901 $propsearchall = !empty($propval['searchall']) ? $propval['searchall'] : 0;
4902 $propisameasure = !empty($propval['isameasure']) ? $propval['isameasure'] : 0;
4903 $propcss = !empty($propval['css']) ? $propval['css'] : '';
4904 $propcssview = !empty($propval['cssview']) ? $propval['cssview'] : '';
4905 $propcsslist = !empty($propval['csslist']) ? $propval['csslist'] : '';
4906 $prophelp = !empty($propval['help']) ? $propval['help'] : '';
4907 $propshowoncombobox = !empty($propval['showoncombobox']) ? $propval['showoncombobox'] : 0;
4908 //$propdisabled=$propval['disabled'];
4909 $propvalidate = !empty($propval['validate']) ? $propval['validate'] : 0;
4910 $propcomment = !empty($propval['comment']) ? $propval['comment'] : '';
4911
4912 print '<!-- line for object property -->'."\n";
4913 print '<tr class="oddeven">';
4914
4915 if (!empty($conf->main_checkbox_left_column)) {
4916 if ($action == 'editproperty' && $propname == $propertykey) {
4917 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
4918 print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Save").'">';
4919 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
4920 print '</td>';
4921 } else {
4922 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
4923 if ($propname != 'rowid') {
4924 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>';
4925 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>';
4926 }
4927 print '</td>';
4928 }
4929 }
4930 print '<td class="tdsticky tdstickygray">';
4931 print dol_escape_htmltag($propname);
4932 print '</td>';
4933 if ($action == 'editproperty' && $propname == $propertykey) {
4934 print '<td>';
4935 print '<input type="hidden" name="propname" value="'.dol_escape_htmltag($propname).'">';
4936 print '<input name="proplabel" class="maxwidth125" value="'.dol_escape_htmltag($proplabel).'">';
4937 print '</td>';
4938 print '<td class="tdoverflowmax150">';
4939 print '<input name="proptype" id="proptype" class="maxwidth125" value="'.dol_escape_htmltag($proptype).'" list="datalistproptype"></input>';
4940 // Use the samedatalist than for create
4941 print '<datalist id="datalistproptype">';
4942 print '<option>varchar(128)</option>';
4943 print '<option>email</option>';
4944 print '<option>phone</option>';
4945 print '<option>ip</option>';
4946 print '<option>url</option>';
4947 print '<option>password</option>';
4948 print '<option>text</option>';
4949 print '<option>html</option>';
4950 print '<option>date</option>';
4951 print '<option>datetime</option>';
4952 print '<option>integer</option>';
4953 print '<option>stars(5)</option>';
4954 print '<option>double(28,4)</option>';
4955 print '<option>real</option>';
4956 print '<option>integer:ClassName:RelativePath/To/ClassFile.class.php[:1[:FILTER]]</option>';
4957 // Combo with list of fields
4958 /*
4959 if (empty($formadmin)) {
4960 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
4961 $formadmin = new FormAdmin($db);
4962 }
4963 print $formadmin->selectTypeOfFields($key, GETPOST($key, 'alpha'));
4964 */
4965 print '</datalist>';
4966
4967 print '</td>';
4968 print '<td class="tdoverflowmax200">';
4969 print '<textarea name="proparrayofkeyval">';
4970 if (isset($proparrayofkeyval)) {
4971 if (is_array($proparrayofkeyval) || $proparrayofkeyval != '') {
4972 print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
4973 }
4974 }
4975 print '</textarea>';
4976 print '</td>';
4977 print '<td>';
4978 print '<input class="center width50" name="propnotnull" value="'.dol_escape_htmltag($propnotnull).'">';
4979 print '</td>';
4980 print '<td>';
4981 print '<input class="maxwidth50" name="propdefault" value="'.dol_escape_htmltag($propdefault).'">';
4982 print '</td>';
4983 print '<td class="center">';
4984 print '<input class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag($propindex).'">';
4985 print '</td>';
4986 print '<td>';
4987 print '<input class="center maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag($propforeignkey).'">';
4988 print '</td>';
4989 print '<td>';
4990 print '<input class="right width50" name="propposition" value="'.dol_escape_htmltag($propposition).'">';
4991 print '</td>';
4992 print '<td>';
4993 print '<input class="center width75" name="propenabled" value="'.dol_escape_htmltag($propenabled).'">';
4994 print '</td>';
4995 print '<td>';
4996 print '<input class="center width75" name="propvisible" value="'.dol_escape_htmltag($propvisible).'">';
4997 print '</td>';
4998 print '<td>';
4999 print '<input class="center width50" name="propnoteditable" size="2" value="'.dol_escape_htmltag($propnoteditable).'">';
5000 print '</td>';
5001 /*print '<td>';
5002 print '<input class="center" name="propalwayseditable" size="2" value="'.dol_escape_htmltag($propalwayseditable).'">';
5003 print '</td>';*/
5004 print '<td>';
5005 print '<input class="center width50" name="propsearchall" value="'.dol_escape_htmltag($propsearchall).'">';
5006 print '</td>';
5007 print '<td>';
5008 print '<input class="center width50" name="propisameasure" value="'.dol_escape_htmltag($propisameasure).'">';
5009 print '</td>';
5010 print '<td>';
5011 print '<input class="center maxwidth50" name="propcss" value="'.dol_escape_htmltag($propcss).'">';
5012 print '</td>';
5013 print '<td>';
5014 print '<input class="center maxwidth50" name="propcssview" value="'.dol_escape_htmltag($propcssview).'">';
5015 print '</td>';
5016 print '<td>';
5017 print '<input class="center maxwidth50" name="propcsslist" value="'.dol_escape_htmltag($propcsslist).'">';
5018 print '</td>';
5019 print '<td>';
5020 print '<input class="maxwidth100" name="prophelp" value="'.dol_escape_htmltag($prophelp).'">';
5021 print '</td>';
5022 print '<td>';
5023 print '<input class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag($propshowoncombobox).'">';
5024 print '</td>';
5025 print '<td>';
5026 print '<input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag($propvalidate).'">';
5027 print '</td>';
5028 print '<td>';
5029 print '<input class="maxwidth100" name="propcomment" value="'.dol_escape_htmltag($propcomment).'">';
5030 print '</td>';
5031 if (empty($conf->main_checkbox_left_column)) {
5032 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5033 print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Save").'">';
5034 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
5035 print '</td>';
5036 }
5037 } else {
5038 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($proplabel).'">';
5039 print dol_escape_htmltag($proplabel);
5040 print '</td>';
5041 print '<td class="tdoverflowmax200">';
5042 $pictoType = '';
5043 $matches = array();
5044 if (preg_match('/^varchar/', $proptype, $matches)) {
5045 $pictoType = 'varchar';
5046 } elseif (preg_match('/^integer:/', $proptype, $matches)) {
5047 $pictoType = 'link';
5048 } elseif (strpos($proptype, 'integer') === 0) {
5049 $pictoType = substr($proptype, 0, 3);
5050 } elseif (strpos($proptype, 'timestamp') === 0) {
5051 $pictoType = 'datetime';
5052 } elseif (strpos($proptype, 'real') === 0) {
5053 $pictoType = 'double';
5054 } elseif (strpos($proptype, 'stars') === 0) {
5055 $pictoType = 'stars';
5056 }
5057 print(!empty($pictoType) ? getPictoForType($pictoType) : getPictoForType($proptype)).'<span title="'.dol_escape_htmltag($proptype).'">'.dol_escape_htmltag($proptype).'</span>';
5058 print '</td>';
5059 print '<td class="tdoverflowmax200">';
5060 if ($proparrayofkeyval) {
5061 print '<span title="'.dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE)).'">';
5062 print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
5063 print '</span>';
5064 }
5065 print '</td>';
5066 print '<td class="center">';
5067 print dol_escape_htmltag($propnotnull);
5068 print '</td>';
5069 print '<td>';
5070 print dol_escape_htmltag($propdefault);
5071 print '</td>';
5072 print '<td class="center">';
5073 print $propindex ? '1' : '';
5074 print '</td>';
5075 print '<td class="center">';
5076 print $propforeignkey ? dol_escape_htmltag($propforeignkey) : '';
5077 print '</td>';
5078 print '<td class="right">';
5079 print dol_escape_htmltag($propposition);
5080 print '</td>';
5081 print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
5082 print $propenabled ? dol_escape_htmltag($propenabled) : '';
5083 print '</td>';
5084 // Visibility
5085 print '<td class="center tdoverflowmax100" title="'.($propvisible ? dol_escape_htmltag($propvisible) : '0').'">';
5086 print $propvisible ? dol_escape_htmltag($propvisible) : '0';
5087 print '</td>';
5088 // Readonly
5089 print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
5090 print $propnoteditable ? dol_escape_htmltag($propnoteditable) : '';
5091 print '</td>';
5092 /*print '<td class="center">';
5093 print $propalwayseditable ? dol_escape_htmltag($propalwayseditable) : '';
5094 print '</td>';*/
5095 print '<td class="center">';
5096 print $propsearchall ? '1' : '';
5097 print '</td>';
5098 print '<td class="center">';
5099 print $propisameasure ? dol_escape_htmltag($propisameasure) : '';
5100 print '</td>';
5101 print '<td class="center tdoverflowmax100" title="'.($propcss ? dol_escape_htmltag($propcss) : '').'">';
5102 print $propcss ? dol_escape_htmltag($propcss) : '';
5103 print '</td>';
5104 print '<td class="center tdoverflowmax100" title="'.($propcssview ? dol_escape_htmltag($propcssview) : '').'">';
5105 print $propcssview ? dol_escape_htmltag($propcssview) : '';
5106 print '</td>';
5107 print '<td class="center tdoverflowmax100" title="'.($propcsslist ? dol_escape_htmltag($propcsslist) : '').'">';
5108 print $propcsslist ? dol_escape_htmltag($propcsslist) : '';
5109 print '</td>';
5110 // Key for tooltop
5111 print '<td class="tdoverflowmax150" title="'.($prophelp ? dol_escape_htmltag($prophelp) : '').'">';
5112 print $prophelp ? dol_escape_htmltag($prophelp) : '';
5113 print '</td>';
5114 print '<td class="center">';
5115 print $propshowoncombobox ? dol_escape_htmltag($propshowoncombobox) : '';
5116 print '</td>';
5117 /*print '<td class="center">';
5118 print $propdisabled?$propdisabled:'';
5119 print '</td>';*/
5120 print '<td class="center">';
5121 print $propvalidate ? dol_escape_htmltag($propvalidate) : '';
5122 print '</td>';
5123 print '<td class="tdoverflowmax200">';
5124 print '<span title="'.dol_escape_htmltag($propcomment).'">';
5125 print dol_escape_htmltag($propcomment);
5126 print '</span>';
5127 print '</td>';
5128 if (empty($conf->main_checkbox_left_column)) {
5129 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5130 if ($propname != 'rowid') {
5131 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>';
5132 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>';
5133 }
5134 print '</td>';
5135 }
5136 }
5137 print '</tr>';
5138 }
5139 } else {
5140 if ($tab == 'specifications') {
5141 if ($action != 'editfile' || empty($file)) {
5142 print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
5143 print '<br>';
5144
5145 $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
5146
5147 foreach ($specs as $spec) {
5148 $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
5149 $format = 'asciidoc';
5150 if (preg_match('/\.md$/i', $spec['name'])) {
5151 $format = 'markdown';
5152 }
5153 print '<span class="fa fa-file"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
5154 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>';
5155 print '<br>';
5156 }
5157 } else {
5158 // Use MD or asciidoc
5159
5160 //print $langs->trans("UseAsciiDocFormat").'<br>';
5161
5162 $fullpathoffile = dol_buildpath($file, 0);
5163
5164 $content = file_get_contents($fullpathoffile);
5165
5166 // New module
5167 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5168 print '<input type="hidden" name="token" value="'.newToken().'">';
5169 print '<input type="hidden" name="action" value="savefile">';
5170 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
5171 print '<input type="hidden" name="tab" value="'.$tab.'">';
5172 print '<input type="hidden" name="module" value="'.$module.'">';
5173
5174 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
5175 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
5176 print '<br>';
5177 print '<center>';
5178 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
5179 print ' &nbsp; ';
5180 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
5181 print '</center>';
5182
5183 print '</form>';
5184 }
5185 }
5186 $langs->load("errors");
5187 print '<tr><td><span class="warning">'.$langs->trans('ErrorModuleBuilderNoFieldProperty').'</warning></td></tr>';
5188 }
5189 print '</table>';
5190 print '</div>';
5191
5192 print '</form>';
5193 } else {
5194 $langs->load("errors");
5195 print '<span class="warning">'.$langs->trans('ErrorModuleBuilderFailedToInit', $tabobj, (string) $db).'</warning>';
5196 }
5197 } catch (Exception $e) {
5198 print 'ee';
5199 print $e->getMessage();
5200 print 'ff';
5201 }
5202 } else {
5203 if (empty($forceddirread)) {
5204 $fullpathoffile = dol_buildpath($file, 0);
5205 } else {
5206 $fullpathoffile = $dirread.'/'.$file;
5207 }
5208
5209 $content = file_get_contents($fullpathoffile);
5210
5211 // New module
5212 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5213 print '<input type="hidden" name="token" value="'.newToken().'">';
5214 print '<input type="hidden" name="action" value="savefile">';
5215 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
5216 print '<input type="hidden" name="tab" value="'.$tab.'">';
5217 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
5218 print '<input type="hidden" name="module" value="'.$module.($forceddirread ? '@'.$dirread : '').'">';
5219
5220 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
5221 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
5222 print '<br>';
5223 print '<center>';
5224 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
5225 print ' &nbsp; ';
5226 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
5227 print '</center>';
5228
5229 print '</form>';
5230 }
5231 }
5232
5233 print dol_get_fiche_end(); // Level 3
5234 }
5235
5236 if ($tab == 'dictionaries') {
5237 print '<!-- tab=dictionaries -->'."\n";
5238 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
5239
5240 $dicts = $moduleobj->dictionaries;
5241
5242 if ($action == 'deletedict') {
5243 $formconfirm = $form->formconfirm(
5244 $_SERVER["PHP_SELF"].'?dictionnarykey='.urlencode((string) (GETPOSTINT('dictionnarykey'))).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)),
5245 $langs->trans('Delete'),
5246 $langs->trans('Confirm Delete Dictionnary', GETPOST('dictionnarykey', 'alpha')),
5247 'confirm_deletedictionary',
5248 '',
5249 0,
5250 1
5251 );
5252 print $formconfirm;
5253 }
5254
5255 if ($action != 'editfile' || empty($file)) {
5256 print '<span class="opacitymedium">';
5257 $htmlhelp = $langs->trans("DictionariesDefDescTooltip", '{s1}');
5258 $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/dict.php">'.$langs->trans('Setup').' - '.$langs->trans('Dictionaries').'</a>', $htmlhelp);
5259 print $form->textwithpicto($langs->trans("DictionariesDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
5260 print '</span>';
5261 print '<br>';
5262
5263 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
5264 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=DICTIONARIES">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
5265 print '<br>';
5266 if (is_array($dicts) && !empty($dicts)) {
5267 print '<span class="fa fa-file"></span> '.$langs->trans("LanguageFile").' :</span> ';
5268 print '<strong class="wordbreak">'.$dicts['langs'].'</strong>';
5269 print '<br>';
5270 }
5271 print '<br>';
5272
5273 $head3 = array();
5274 $h = 0;
5275
5276 // Dir for module
5277 //$dir = $dirread.'/'.$modulelowercase.'/class';
5278
5279 $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=newdictionary';
5280 $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewDictionary").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
5281 $head3[$h][2] = 'newdictionary';
5282 $h++;
5283
5284 // Scan for object class files
5285 //$listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
5286
5287 $firstdicname = '';
5288 // if (!empty($dicts['tabname'])) {
5289 // foreach ($dicts['tabname'] as $key => $dic) {
5290 // $dicname = $dic;
5291 // $diclabel = $dicts['tablib'][$key];
5292
5293 // if (empty($firstdicname)) {
5294 // $firstdicname = $dicname;
5295 // }
5296
5297 // $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic='.$dicname;
5298 // $head3[$h][1] = $diclabel;
5299 // $head3[$h][2] = $dicname;
5300 // $h++;
5301 // }
5302 // }
5303
5304 // if ($h > 1) {
5305 // $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=deletedictionary';
5306 // $head3[$h][1] = $langs->trans("DangerZone");
5307 // $head3[$h][2] = 'deletedictionary';
5308 // $h++;
5309 // }
5310
5311 // 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.
5312 // if ($tabdic == 'newdicifnodic') {
5313 // if ($firstdicname) {
5314 // $tabdic = $firstdicname;
5315 // } else {
5316 // $tabdic = 'newdictionary';
5317 // }
5318 // }
5319 //print dol_get_fiche_head($head3, $tabdic, '', -1, ''); // Level 3
5320
5321
5322 $newdict = dolGetButtonTitle($langs->trans('NewDictionary'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/modulebuilder/index.php?tab=dictionaries&module='.urlencode($module).'&tabdic=newdictionary');
5323 print_barre_liste($langs->trans("ListOfDictionariesEntries"), 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, '', '', 0, $newdict, '', 0, 0, 0, 1);
5324
5325 if ($tabdic != 'newdictionary') {
5326 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5327 print '<input type="hidden" name="token" value="'.newToken().'">';
5328 print '<input type="hidden" name="action" value="addDictionary">';
5329 print '<input type="hidden" name="tab" value="dictionaries">';
5330 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5331 print '<input type="hidden" name="tabdic" value="'.dol_escape_htmltag($tabdic).'">';
5332
5333 print '<div class="div-table-responsive">';
5334 print '<table class="noborder">';
5335
5336 print '<tr class="liste_titre">';
5337 print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'thsticky thstickygrey ');
5338 print_liste_field_titre("Table", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5339 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5340 print_liste_field_titre("SQL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5341 print_liste_field_titre("SQLSort", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5342 print_liste_field_titre("FieldsView", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5343 print_liste_field_titre("FieldsEdit", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5344 print_liste_field_titre("FieldsInsert", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5345 print_liste_field_titre("Rowid", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5346 print_liste_field_titre("Condition", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5347 print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5348 print "</tr>\n";
5349
5350 if (!empty($dicts) && is_array($dicts) && !empty($dicts['tabname']) && is_array($dicts['tabname'])) {
5351 $i = 0;
5352 $maxi = count($dicts['tabname']);
5353 while ($i < $maxi) {
5354 if ($action == 'editdict' && $i == GETPOSTINT('dictionnarykey') - 1) {
5355 print '<tr class="oddeven">';
5356 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5357 print '<input type="hidden" name="token" value="'.newToken().'">';
5358 print '<input type="hidden" name="tab" value="dictionaries">';
5359 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5360 print '<input type="hidden" name="action" value="updatedictionary">';
5361 print '<input type="hidden" name="dictionnarykey" value="'.($i + 1).'">';
5362
5363 print '<td class="tdsticky tdstickygray">';
5364 print($i + 1);
5365 print '</td>';
5366
5367 print '<td>';
5368 print '<input type="text" name="tabname" value="'.$dicts['tabname'][$i].'" readonly class="tdstickygray">';
5369 print '</td>';
5370
5371 print '<td>';
5372 print '<input type="text" name="tablib" value="'.$dicts['tablib'][$i].'">';
5373 print '</td>';
5374
5375 print '<td>';
5376 print '<input type="text" name="tabsql" value="'.$dicts['tabsql'][$i].'" readonly class="tdstickygray">';
5377 print '</td>';
5378
5379 print '<td>';
5380 print '<select name="tabsqlsort">';
5381 print '<option value="'.dol_escape_htmltag($dicts['tabsqlsort'][$i]).'">'.$dicts['tabsqlsort'][$i].'</option>';
5382 print '</select>';
5383 print '</td>';
5384
5385 print '<td><select name="tabfield" >';
5386 print '<option value="'.dol_escape_htmltag($dicts['tabfield'][$i]).'">'.$dicts['tabfield'][$i].'</option>';
5387 print '</select></td>';
5388
5389 print '<td><select name="tabfieldvalue" >';
5390 print '<option value="'.dol_escape_htmltag($dicts['tabfieldvalue'][$i]).'">'.$dicts['tabfieldvalue'][$i].'</option>';
5391 print '</select></td>';
5392
5393 print '<td><select name="tabfieldinsert" >';
5394 print '<option value="'.dol_escape_htmltag($dicts['tabfieldinsert'][$i]).'">'.$dicts['tabfieldinsert'][$i].'</option>';
5395 print '</select></td>';
5396
5397 print '<td>';
5398 print '<input type="text" name="tabrowid" value="'.dol_escape_htmltag($dicts['tabrowid'][$i]).'" readonly class="tdstickygray">';
5399 print '</td>';
5400
5401 print '<td>';
5402 print '<input type="text" name="tabcond" value="'.dol_escape_htmltag((empty($dicts['tabcond'][$i]) ? 'disabled' : 'enabled')).'" readonly class="tdstickygray">';
5403 print '</td>';
5404
5405 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5406 print '<input id ="updatedict" class="reposition button smallpaddingimp" type="submit" name="updatedict" value="'.$langs->trans("Modify").'"/>';
5407 print '<br>';
5408 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
5409 print '</td>';
5410
5411 print '</form>';
5412 print '</tr>';
5413 } else {
5414 print '<tr class="oddeven">';
5415
5416 print '<td class="tdsticky tdstickygray">';
5417 print($i + 1);
5418 print '</td>';
5419
5420 print '<td>';
5421 print $dicts['tabname'][$i];
5422 print '</td>';
5423
5424 print '<td>';
5425 print $dicts['tablib'][$i];
5426 print '</td>';
5427
5428 print '<td>';
5429 print $dicts['tabsql'][$i];
5430 print '</td>';
5431
5432 print '<td>';
5433 print $dicts['tabsqlsort'][$i];
5434 print '</td>';
5435
5436 print '<td>';
5437 print $dicts['tabfield'][$i];
5438 print '</td>';
5439
5440 print '<td>';
5441 print $dicts['tabfieldvalue'][$i];
5442 print '</td>';
5443
5444 print '<td>';
5445 print $dicts['tabfieldinsert'][$i];
5446 print '</td>';
5447
5448 print '<td >';
5449 print $dicts['tabrowid'][$i];
5450 print '</td>';
5451
5452 print '<td >';
5453 print $dicts['tabcond'][$i];
5454 print '</td>';
5455
5456 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5457 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=editdict&token='.newToken().'&dictionnarykey='.urlencode((string) ($i + 1)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'">'.img_edit().'</a>';
5458 print '<a class="marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=deletedict&token='.newToken().'&dictionnarykey='.urlencode((string) ($i + 1)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'">'.img_delete().'</a>';
5459 print '</td>';
5460
5461 print '</tr>';
5462 }
5463 $i++;
5464 }
5465 } else {
5466 print '<tr><td colspan="11"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
5467 }
5468
5469 print '</table>';
5470 print '</div>';
5471
5472 print '</form>';
5473 }
5474
5475 if ($tabdic == 'newdictionary') {
5476 // New dic tab
5477 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5478 print '<input type="hidden" name="token" value="'.newToken().'">';
5479 print '<input type="hidden" name="action" value="initdic">';
5480 print '<input type="hidden" name="tab" value="dictionaries">';
5481 print '<input type="hidden" name="tabdic" value="'.$tabdic.'">';
5482
5483 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5484
5485 print '<span class="opacitymedium">'.$langs->trans("EnterNameOfDictionaryDesc").'</span><br><br>';
5486
5487 print dol_get_fiche_head();
5488 print '<table class="border centpercent">';
5489 print '<tbody>';
5490 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Table").'</td><td><input type="text" name="dicname" maxlength="64" value="'.dol_escape_htmltag(GETPOST('dicname', 'alpha') ? GETPOST('dicname', 'alpha') : $modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("DicKey")).'" autofocus></td>';
5491 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Label").'</td><td><input type="text" name="label" value="'.dol_escape_htmltag(GETPOST('label', 'alpha')).'"></td></tr>';
5492 print '<tr><td class="titlefieldcreate">'.$langs->trans("SQL").'</td><td><input type="text" style="width:50%;" name="sql" value="'.dol_escape_htmltag(GETPOST('sql', 'alpha')).'"></td></tr>';
5493 print '<tr><td class="titlefieldcreate">'.$langs->trans("SQLSort").'</td><td><input type="text" name="sqlsort" value="'.dol_escape_htmltag(GETPOST('sqlsort', 'alpha')).'" readonly></td></tr>';
5494 print '<tr><td class="titlefieldcreate">'.$langs->trans("FieldsView").'</td><td><input type="text" name="field" value="'.dol_escape_htmltag(GETPOST('field', 'alpha')).'"></td></tr>';
5495 print '<tr><td class="titlefieldcreate">'.$langs->trans("FieldsEdit").'</td><td><input type="text" name="fieldvalue" value="'.dol_escape_htmltag(GETPOST('fieldvalue', 'alpha')).'"></td></tr>';
5496 print '<tr><td class="titlefieldcreate">'.$langs->trans("FieldsInsert").'</td><td><input type="text" name="fieldinsert" value="'.dol_escape_htmltag(GETPOST('fieldinsert', 'alpha')).'"></td></tr>';
5497 print '<tr><td class="titlefieldcreate">'.$langs->trans("Rowid").'</td><td><input type="text" name="rowid" value="'.dol_escape_htmltag(GETPOST('rowid', 'alpha')).'"></td></tr>';
5498 print '<tr></tr>';
5499 print '</tbody></table>';
5500 print '<input type="submit" class="button" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
5501 print '<input id="cancel" type="submit" class="button" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
5502 print dol_get_fiche_end();
5503 print '</form>';
5504 print '<script>
5505 $(document).ready(function() {
5506 $("input[name=\'dicname\']").on("blur", function() {
5507 if ($(this).val().length > 0) {
5508 $("input[name=\'label\']").val($(this).val());
5509 $("input[name=\'sql\']").val("SELECT f.rowid as rowid, f.code, f.label, f.active FROM llx_c_" + $(this).val() + " as f");
5510 $("input[name=\'sqlsort\']").val("label ASC");
5511 $("input[name=\'field\']").val("code,label");
5512 $("input[name=\'fieldvalue\']").val("code,label");
5513 $("input[name=\'fieldinsert\']").val("code,label");
5514 $("input[name=\'rowid\']").val("rowid");
5515 } else {
5516 $("input[name=\'label\']").val("");
5517 $("input[name=\'sql\']").val("");
5518 $("input[name=\'sqlsort\']").val("");
5519 $("input[name=\'field\']").val("");
5520 $("input[name=\'fieldvalue\']").val("");
5521 $("input[name=\'fieldinsert\']").val("");
5522 $("input[name=\'rowid\']").val("");
5523 }
5524 });
5525 $("input[id=\'cancel\']").click(function() {
5526 window.history.back();
5527 });
5528 });
5529 </script>';
5530
5531 /*print '<br>';
5532 print '<br>';
5533 print '<br>';
5534 print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
5535 print '<br>';
5536 print '<br>';
5537 //print '<input type="checkbox" name="initfromtablecheck"> ';
5538 print $langs->trans("InitStructureFromExistingTable");
5539 print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
5540 print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
5541 print '<br>';
5542 */
5543 } elseif ($tabdic == 'deletedictionary') {
5544 // Delete dic tab
5545 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5546 print '<input type="hidden" name="token" value="'.newToken().'">';
5547 print '<input type="hidden" name="action" value="confirm_deletedictionary">';
5548 print '<input type="hidden" name="tab" value="dictionaries">';
5549 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5550
5551 print $langs->trans("EnterNameOfDictionnaryToDeleteDesc").'<br><br>';
5552
5553 print '<input type="text" name="dicname" value="'.dol_escape_htmltag($modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("DicKey")).'">';
5554 print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
5555 print '</form>';
5556 }
5557
5558 print dol_get_fiche_end();
5559 } else {
5560 $fullpathoffile = dol_buildpath($file, 0);
5561
5562 $content = file_get_contents($fullpathoffile);
5563
5564 // New module
5565 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5566 print '<input type="hidden" name="token" value="'.newToken().'">';
5567 print '<input type="hidden" name="action" value="savefile">';
5568 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
5569 print '<input type="hidden" name="tab" value="'.$tab.'">';
5570 print '<input type="hidden" name="module" value="'.$module.'">';
5571
5572 $posCursor = (empty($find)) ? array() : array('find' => $find);
5573 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
5574 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
5575 print '<br>';
5576 print '<center>';
5577 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
5578 print ' &nbsp; ';
5579 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
5580 print '</center>';
5581
5582 print '</form>';
5583 }
5584 }
5585
5586 if ($tab == 'menus') {
5587 print '<!-- tab=menus -->'."\n";
5588 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
5589 $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
5590 $destdir = $dirins.'/'.strtolower($module);
5591 $listofobject = dol_dir_list($destdir.'/class', 'files', 0, '\.class\.php$');
5592 $objects = dolGetListOfObjectClasses($destdir);
5593
5594 $leftmenus = array();
5595
5596 $menus = $moduleobj->menu;
5597
5598 $permissions = $moduleobj->rights;
5599 $crud = array('read' => 'CRUDRead', 'write' => 'CRUDCreateWrite', 'delete' => 'Delete');
5600
5601 //grouped permissions
5602 $groupedRights = array();
5603 foreach ($permissions as $right) {
5604 $key = $right[4];
5605 if (!isset($groupedRights[$key])) {
5606 $groupedRights[$key] = array();
5607 }
5608 $groupedRights[$key][] = $right;
5609 }
5610 $groupedRights_json = json_encode($groupedRights);
5611
5612 if ($action == 'deletemenu') {
5613 $formconfirms = $form->formconfirm(
5614 $_SERVER["PHP_SELF"].'?menukey='.urlencode((string) (GETPOSTINT('menukey'))).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)),
5615 $langs->trans('Delete'),
5616 ($menus[GETPOST('menukey')]['fk_menu'] === 'fk_mainmenu='.strtolower($module) ? $langs->trans('Warning: you will delete all menus linked to this one.', GETPOSTINT('menukey')) : $langs->trans('Confirm Delete Menu', GETPOSTINT('menukey'))),
5617 'confirm_deletemenu',
5618 '',
5619 0,
5620 1
5621 );
5622 print $formconfirms;
5623 }
5624 if ($action != 'editfile' || empty($file)) {
5625 print '<span class="opacitymedium">';
5626 $htmlhelp = $langs->trans("MenusDefDescTooltip", '{s1}');
5627 $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/menus/index.php">'.$langs->trans('Setup').' - '.$langs->trans('Menus').'</a>', $htmlhelp);
5628 print $form->textwithpicto($langs->trans("MenusDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
5629 print '</span>';
5630 print '<br>';
5631
5632 // Links to editable files
5633 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
5634 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=TOPMENU">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
5635 print '<br>';
5636
5637 // Search all files of modules mentioned by menu
5638 $listODifferentUrlsInMenu = array();
5639 foreach ($menus as $obj) {
5640 if (preg_match('/^\/'.preg_quote(strtolower($module), '/').'\//', $obj['url']) && !empty($pathoffile)) {
5641 if (!empty($listODifferentUrlsInMenu[$pathoffile])) { // Test to avoid to show same file twice.
5642 continue;
5643 }
5644 $pathtofile = $obj['url'];
5645 $listODifferentUrlsInMenu[$pathoffile] = $pathtofile;
5646 print '<span class="fa fa-file"></span> '.$langs->trans("PageLinkedByAMenuEntry").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
5647 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=TOPMENU">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
5648 print '<br>';
5649 }
5650 }
5651
5652
5653 print '<br>';
5654 print load_fiche_titre($langs->trans("ListOfMenusEntries"), '', '');
5655
5656 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5657 print '<input type="hidden" name="token" value="'.newToken().'">';
5658 print '<input type="hidden" name="action" value="addmenu">';
5659 print '<input type="hidden" name="tab" value="menus">';
5660 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5661 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
5662
5663 print '<div class="div-table-responsive">';
5664 print '<table class="noborder small">';
5665
5666 $htmltextenabled = '<u>'.$langs->trans("Examples").':</u><br>';
5667 $htmltextenabled .= '1 <span class="opacitymedium">(module always enabled)</span><br>';
5668 $htmltextenabled .= '0 <span class="opacitymedium">(module always disabled)</span><br>';
5669 $htmltextenabled .= 'isModEnabled(\''.dol_escape_htmltag(strtolower($module)).'\') <span class="opacitymedium">(enabled when module is enabled)</span>';
5670 $htmltextperms = '<u>'.$langs->trans("Examples").':</u><br>';
5671 $htmltextperms .= '1 <span class="opacitymedium">(access always allowed)</span><br>';
5672 $htmltextperms .= '$user->hasright(\''.dol_escape_htmltag(strtolower($module)).'\', \'myobject\', \'read\') <span class="opacitymedium">(access allowed if user has permission module->object->read)</span>';
5673
5674 print '<tr class="liste_titre">';
5675 print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center tdsticky tdstickygray ');
5676 print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5677 print_liste_field_titre("Title", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center');
5678 print_liste_field_titre("LinkToParentMenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'minwidth100 ');
5679 print_liste_field_titre("mainmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5680 print_liste_field_titre("leftmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5681 print_liste_field_titre("URL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->transnoentitiesnoconv('DetailUrl'));
5682 print_liste_field_titre("LanguageFile", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
5683 print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'right ');
5684 print_liste_field_titre("Enabled", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans('DetailEnabled').'<br><br>'.$htmltextenabled);
5685 print_liste_field_titre("Rights", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailRight').'<br><br>'.$htmltextperms);
5686 print_liste_field_titre("Target", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailTarget'));
5687 print_liste_field_titre("MenuForUsers", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center minwidth100 ', $langs->trans('DetailUser'));
5688 print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans(''));
5689 print "</tr>\n";
5690
5691 $r = count($menus) + 1;
5692 // for adding menu on module
5693 print '<tr>';
5694 print '<td class="center tdsticky tdstickygray"><input type="hidden" readonly class="center maxwidth50" name="propenabled" value="#"></td>';
5695 print '<td class="center">';
5696 print '<select class="maxwidth50" name="type">';
5697 print '<option value="">'.$langs->trans("........").'</option><option value="'.dol_escape_htmltag("left").'">left</option><option value="'.dol_escape_htmltag("top").'">top</option>';
5698 print '</select></td>';
5699 print '<td class="left"><input type="text" class="left maxwidth100" name="titre" value="'.dol_escape_htmltag(GETPOST('titre', 'alpha')).'"></td>';
5700 print '<td class="left">';
5701 print '<select name="fk_menu">';
5702 print '<option value="">'.$langs->trans("........").'</option>';
5703 foreach ($menus as $obj) {
5704 if ($obj['type'] == 'left' && !empty($obj['leftmenu'])) {
5705 print "<option value=".strtolower($obj['leftmenu']).">".$obj['leftmenu']."</option>";
5706 }
5707 }
5708 print '</select>';
5709 print '</td>';
5710 print '<td class="left"><input type="text" class="left maxwidth50" name="mainmenu" value="'.(empty(GETPOST('mainmenu')) ? strtolower($module) : dol_escape_htmltag(GETPOST('mainmenu', 'alpha'))).'"></td>';
5711 print '<td class="center"><input id="leftmenu" type="text" class="left maxwidth50" name="leftmenu" value="'.dol_escape_htmltag(GETPOST('leftmenu', 'alpha')).'"></td>';
5712 // URL
5713 print '<td class="left"><input id="url" type="text" class="left maxwidth100" name="url" value="'.dol_escape_htmltag(GETPOST('url', 'alpha')).'"></td>';
5714 print '<td class="left"><input type="text" class="left maxwidth75" name="langs" value="'.strtolower($module).'@'.strtolower($module).'" readonly></td>';
5715 // Position
5716 print '<td class="center"><input type="text" class="center maxwidth50 tdstickygray" name="position" value="'.(1000 + $r).'" readonly></td>';
5717 // Enabled
5718 print '<td class="center">';
5719 print '<input type="enabled" class="maxwidth125" value="'.dol_escape_htmltag(GETPOSTISSET('enabled') ? GETPOST('enabled') : 'isModEnabled(\''.$module.'\')').'">';
5720 /*
5721 print '<select class="maxwidth" name="enabled">';
5722 print '<option value="1" selected>'.$langs->trans("Show").'</option>';
5723 print '<option value="0">'.$langs->trans("Hide").'</option>';
5724 print '</select>';
5725 */
5726 print '</td>';
5727 // Perms
5728 print '<td class="left">';
5729 print '<select class="maxwidth" name="objects" id="objects">';
5730 print '<option value=""></option>';
5731 if (is_array($objects)) {
5732 foreach ($objects as $value) {
5733 print '<option value="'.strtolower($value).'">'.dol_escape_htmltag(strtolower($value)).'</option>';
5734 }
5735 }
5736 print '</select>';
5737 print '<select class="maxwidth hideobject" name="perms" id="perms">';
5738 print '</select>';
5739 print '</td>';
5740 print '<td class="center"><input type="text" class="center maxwidth50" name="target" value="'.dol_escape_htmltag(GETPOST('target', 'alpha')).'"></td>';
5741 print '<td class="center"><select class="maxwidth10" name="user"><option value="2">'.$langs->trans("AllMenus").'</option><option value="0">'.$langs->trans("Internal").'</option><option value="1">'.$langs->trans("External").'</option></select></td>';
5742
5743 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5744 print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
5745 print '</td>';
5746 print '</tr>';
5747 // end form for add menu
5748
5749 //var_dump($menus);
5750
5751 // Loop on each menu entry
5752 if (count($menus)) {
5753 $i = 0;
5754 foreach ($menus as $menu) {
5755 $i++;
5756 //for get parent in menu
5757 $string = dol_escape_htmltag($menu['fk_menu']);
5758 $value = substr($string, strpos($string, 'fk_leftmenu=') + strlen('fk_leftmenu='));
5759
5760 $propFk_menu = !empty($menu['fk_menu']) ? $menu['fk_menu'] : GETPOST('fk_menu');
5761 $propTitre = !empty($menu['titre']) ? $menu['titre'] : GETPOST('titre');
5762 $propMainmenu = !empty($menu['mainmenu']) ? $menu['mainmenu'] : GETPOST('mainmenu');
5763 $propLeftmenu = !empty($menu['leftmenu']) ? $menu['leftmenu'] : GETPOST('leftmenu');
5764 $propUrl = !empty($menu['url']) ? $menu['url'] : GETPOST('url', 'alpha');
5765 $propPerms = !empty($menu['perms']) ? $menu['perms'] : GETPOST('perms');
5766 $propUser = !empty($menu['user']) ? $menu['user'] : GETPOST('user');
5767 $propTarget = !empty($menu['target']) ? $menu['target'] : GETPOST('target');
5768 $propEnabled = !empty($menu['enabled']) ? $menu['enabled'] : GETPOST('enabled');
5769
5770 $objPerms = (empty($arguments[1]) ? '' : trim($arguments[1]));
5771 $valPerms = (empty($arguments[2]) ? '' : trim($arguments[2]));
5772
5773 //$tabobject = ''; // We can't know what is $tabobject in most cases
5774
5775 if ($action == 'editmenu' && GETPOSTINT('menukey') == $i) {
5776 //var_dump($propPerms);exit;
5777 print '<tr class="oddeven">';
5778 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
5779 print '<input type="hidden" name="token" value="'.newToken().'">';
5780 print '<input type="hidden" name="action" value="update_menu">';
5781 print '<input type="hidden" name="tab" value="menus">';
5782 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
5783 print '<input type="hidden" name="menukey" value="'.$i.'"/>';
5784 //print '<input type="hidden" name="tabobject" value="'.dol_escape_htmltag($tabobject).'">';
5785 print '<td class="tdsticky tdstickygray">';
5786 print $i;
5787 print '</td>';
5788 // Position (top, left)
5789 print '<td class="center">
5790 <select class="center maxwidth50" name="type">
5791 <option value="'.dol_escape_htmltag($menu['type']).'">
5792 '.dol_escape_htmltag($menu['type']).'
5793 </option>';
5794 print '<option value="'.($menu['type'] == 'left' ? 'top' : 'left').'">';
5795 if ($menu['type'] == 'left') {
5796 print 'top';
5797 } else {
5798 print 'left';
5799 }
5800 print '</option></select></td>';
5801 // Title
5802 print '<td><input type="text" class="left maxwidth100" name="titre" value="'.dol_escape_htmltag($propTitre).'"></td>';
5803 // Parent menu
5804 print '<td>';
5805 /*print '<select name="fk_menu" class="left maxwidth">';
5806 print '<option value="'.dol_escape_htmltag($propFk_menu).'">'.dol_escape_htmltag($value).'</option>';
5807 foreach ($menus as $obj) {
5808 if ($obj['type'] == 'left' && $obj['leftmenu'] != $value && $obj['leftmenu'] != $menu['leftmenu']) {
5809 print "<option value=".strtolower($obj['leftmenu']).">".$obj['leftmenu']."</option>";
5810 }
5811 }
5812 print '</select>';*/
5813 print '<input type="text" name="fk_menu" class="maxwidth150" value="'.dol_escape_htmltag($propFk_menu).'">';
5814 print '</td>';
5815 print '<td><input type="text" class="left maxwidth50" name="mainmenu" value="'.dol_escape_htmltag($propMainmenu).'" readonly></td>';
5816 print '<td><input type="text" class="left maxwidth50" name="leftmenu" value="'.dol_escape_htmltag($propLeftmenu).'" readonly></td>';
5817 // URL
5818 print '<td><input type="text" class="left maxwidth250" name="url" value="'.dol_escape_htmltag($propUrl).'"></td>';
5819 print '<td><input type="text" class="left maxwidth50" name="langs" value="'.strtolower($module).'@'.strtolower($module).'" readonly></td>';
5820 // Position
5821 print '<td class="center"><input type="text" class="center maxwidth50 tdstickygray" name="position" value="'.($menu['position']).'" readonly></td>';
5822 // Enabled
5823 print '<td class="nowraponall">';
5824 print '<input type="text" class="maxwidth125" name="enabled" value="'.dol_escape_htmltag($propEnabled != '' ? $propEnabled : "isModEnabled('".dol_escape_htmltag($module)."')").'">';
5825 $htmltext = '<u>'.$langs->trans("Examples").':</u><br>';
5826 $htmltext .= '1 <span class="opacitymedium">(always enabled)</span><br>';
5827 $htmltext .= '0 <span class="opacitymedium">(always disabled)</span><br>';
5828 $htmltext .= 'isModEnabled(\''.dol_escape_htmltag($module).'\') <span class="opacitymedium">(enabled when module is enabled)</span><br>';
5829 print $form->textwithpicto('', $htmltext);
5830 /*
5831 print '<select class="maxwidth50" name="enabledselect">';
5832 print '<option value="1">1 (always enabled)</option>';
5833 print '<option value="0">0 (always disabled)</option>';
5834 print '<option value="isModEnabled(\''.dol_escape_htmltag($module).'\')" >isModEnabled(\''.dol_escape_htmltag($module).'\')</option>';
5835 print '</select>';
5836 */
5837 print '</td>';
5838 // Permissions
5839 print '<td class="nowraponall">';
5840 print '<input type="text" name="perms" value="'.dol_escape_htmltag($propPerms).'">';
5841 /*
5842 if (!empty($objPerms)) {
5843 print '<input type="hidden" name="objects" value="'.$objPerms.'" />';
5844 print '<select class="center maxwidth50" name="perms">';
5845 if (!empty($valPerms)) {
5846 print '<option selected value="'.dol_escape_htmltag($valPerms).'">'.dol_escape_htmltag($langs->trans($crud[$valPerms])).'</option>';
5847 foreach ($crud as $key => $val) {
5848 if ($valPerms != $key) {
5849 print '<option value="'.dol_escape_htmltag($key).'">'.dol_escape_htmltag($langs->trans($val)).'</option>';
5850 }
5851 }
5852 }
5853 print '</select>';
5854 } else {
5855 print '<select class="center maxwidth50" name="objects">';
5856 print '<option></option>';
5857 foreach ($objects as $obj) {
5858 print '<option value="'.dol_escape_htmltag(strtolower($obj)).'">'.dol_escape_htmltag($obj).'</option>';
5859 }
5860 print '</select>';
5861 print '<select class="center maxwidth50" name="perms">';
5862 foreach ($crud as $key => $val) {
5863 print '<option value="'.dol_escape_htmltag($key).'">'.dol_escape_htmltag($key).'</option>';
5864 }
5865 print '</select>';
5866 }*/
5867 print '</td>';
5868 // Target
5869 print '<td class="center"><input type="text" class="center maxwidth50" name="target" value="'.dol_escape_htmltag($propTarget).'"></td>';
5870 print '<td class="center"><select class="center maxwidth10" name="user"><option value="2">'.$langs->trans("AllMenus").'</option><option value="0">'.$langs->trans("Internal").'</option><option value="1">'.$langs->trans("External").'</option></select></td>';
5871 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite maxwidth75">';
5872 print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Modify").'">';
5873 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
5874 print '</td>';
5875 print '</form>';
5876 print '</tr>';
5877 } else {
5878 print '<tr class="oddeven">';
5879
5880 print '<td class="tdsticky tdstickygray">';
5881 print $i;
5882 print '</td>';
5883
5884 print '<td class="center">';
5885 print dol_escape_htmltag($menu['type']);
5886 print '</td>';
5887
5888 // Title
5889 print '<td>';
5890 print dol_escape_htmltag($menu['titre']);
5891 print '</td>';
5892
5893 // Parent menu
5894 print '<td class="tdoverflowmax100" title="'.dol_escape_htmltag($menu['fk_menu']).'">';
5895 print dol_escape_htmltag($menu['fk_menu']);
5896 print '</td>';
5897
5898 print '<td>';
5899 print dol_escape_htmltag($menu['mainmenu']);
5900 print '</td>';
5901
5902 print '<td>';
5903 print dol_escape_htmltag($menu['leftmenu']);
5904 print '</td>';
5905
5906 print '<td class="tdoverflowmax250" title="'.dol_escape_htmltag($menu['url']).'">';
5907 print dol_escape_htmltag($menu['url']);
5908 print '</td>';
5909
5910 print '<td>';
5911 print dol_escape_htmltag($menu['langs']);
5912 print '</td>';
5913
5914 // Position
5915 print '<td class="center">';
5916 print dol_escape_htmltag((string) $menu['position']);
5917 print '</td>';
5918
5919 // Enabled
5920 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($menu['enabled']).'">';
5921 print dol_escape_htmltag($menu['enabled']);
5922 print '</td>';
5923
5924 // Perms
5925 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($menu['perms']).'">';
5926 print dol_escape_htmltag($langs->trans($menu['perms']));
5927 print '</td>';
5928
5929 // Target
5930 print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['target']).'">';
5931 print dol_escape_htmltag($menu['target']);
5932 print '</td>';
5933
5934 print '<td class="center">';
5935 if ($menu['user'] == 2) {
5936 print $langs->trans("AllMenus");
5937 } elseif ($menu['user'] == 0) {
5938 print $langs->trans('Internal');
5939 } elseif ($menu['user'] == 1) {
5940 print $langs->trans('External');
5941 } else {
5942 print $menu['user']; // should not happen
5943 }
5944 print '</td>';
5945 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
5946 if ($menu['titre'] != 'Module'.$module.'Name') {
5947 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=editmenu&token='.newToken().'&menukey='.urlencode((string) ($i)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'&tabobj='.urlencode((string) ($tabobj)).'">'.img_edit().'</a>';
5948 print '<a class="deletefielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=deletemenu&token='.newToken().'&menukey='.urlencode((string) ($i - 1)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'">'.img_delete().'</a>';
5949 }
5950 print '</td>';
5951 }
5952 print '</tr>';
5953 }
5954 } else {
5955 print '<tr><td colspan="14"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
5956 }
5957
5958 print '</table>';
5959 print '</div>';
5960 print '</form>';
5961
5962
5963 print '<script>
5964 $(document).ready(function() {
5965 //for fill in auto url
5966 $("#leftmenu").on("input", function() {
5967 var inputLeftMenu = $("#leftmenu").val();
5968 if (inputLeftMenu !== \'\') {
5969 var url = \''.dol_escape_js(strtolower($module)).'\' + inputLeftMenu + \'.php\';
5970 $("#url").val(url);
5971 }else {
5972 $("#url").val("");
5973 }
5974 });
5975
5976 var groupedRights = ' . $groupedRights_json . ';
5977 var objectsSelect = $("select[id=\'objects\']");
5978 var permsSelect = $("select[id=\'perms\']");
5979
5980 objectsSelect.change(function() {
5981 var selectedObject = $(this).val();
5982
5983 permsSelect.empty();
5984
5985 var rights = groupedRights[selectedObject];
5986
5987 if (rights) {
5988 for (var i = 0; i < rights.length; i++) {
5989 var right = rights[i];
5990 var option = $("<option></option>").attr("value", right[5]).text(right[5]);
5991 permsSelect.append(option);
5992 }
5993 } else {
5994 var option = $("<option></option>").attr("value", "read").text("read");
5995 permsSelect.append(option);
5996 }
5997
5998 if (selectedObject !== "" && selectedObject !== null && rights) {
5999 permsSelect.show();
6000 } else {
6001 permsSelect.hide();
6002 }
6003 if (objectsSelect.val() === "" || objectsSelect.val() === null) {
6004 permsSelect.hide();
6005 }
6006 });
6007 });
6008 </script>';
6009
6010 // display permissions for each object
6011 } else {
6012 $fullpathoffile = dol_buildpath($file, 0);
6013
6014 $content = file_get_contents($fullpathoffile);
6015
6016 // New module
6017 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6018 print '<input type="hidden" name="token" value="'.newToken().'">';
6019 print '<input type="hidden" name="action" value="savefile">';
6020 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6021 print '<input type="hidden" name="tab" value="'.$tab.'">';
6022 print '<input type="hidden" name="module" value="'.$module.'">';
6023
6024 $posCursor = (empty($find)) ? array() : array('find' => $find);
6025 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6026 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6027 print '<br>';
6028 print '<center>';
6029 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6030 print ' &nbsp; ';
6031 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6032 print '</center>';
6033
6034 print '</form>';
6035 }
6036 }
6037
6038 if ($tab == 'permissions') {
6039 print '<!-- tab=permissions -->'."\n";
6040 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6041
6042 $perms = $moduleobj->rights;
6043
6044 // Get list of existing objects
6045 $dir = $dirread.'/'.$modulelowercase.'/class';
6046 $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
6047 $objects = array('myobject');
6048 $reg = array();
6049 foreach ($listofobject as $fileobj) {
6050 $tmpcontent = file_get_contents($fileobj['fullname']);
6051 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
6052 $objects[$fileobj['fullname']] = $reg[1];
6053 }
6054 }
6055
6056 // declared select list for actions and labels permissions
6057 $crud = array('read' => 'CRUDRead', 'write' => 'CRUDCreateWrite', 'delete' => 'Delete');
6058 $labels = array("Read objects of ".$module, "Create/Update objects of ".$module, "Delete objects of ".$module);
6059
6060 $action = GETPOST('action', 'alpha');
6061
6062 if ($action == 'deleteright') {
6063 $formconfirm = $form->formconfirm(
6064 $_SERVER["PHP_SELF"].'?permskey='.urlencode((string) (GETPOSTINT('permskey'))).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'&tabobj='.urlencode((string) ($tabobj)),
6065 $langs->trans('Delete'),
6066 $langs->trans('Confirm Delete Right', GETPOST('permskey', 'alpha')),
6067 'confirm_deleteright',
6068 '',
6069 0,
6070 1
6071 );
6072 print $formconfirm;
6073 }
6074
6075 if ($action != 'editfile' || empty($file)) {
6076 print '<!-- Tab to manage permissions -->'."\n";
6077 print '<span class="opacitymedium">';
6078 $htmlhelp = $langs->trans("PermissionsDefDescTooltip");
6079 //$htmlhelp = $langs->trans("PermissionsDefDescTooltip", '{s1}');
6080 //$htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/perms.php">'.$langs->trans('DefaultRights').'</a>', $htmlhelp);
6081 print $form->textwithpicto($langs->trans("PermissionsDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
6082 print '</span>';
6083 print '<br>';
6084
6085 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6086 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=PERMISSIONS">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6087 print '<br>';
6088
6089 print '<br>';
6090 print load_fiche_titre($langs->trans("ListOfPermissionsDefined"), '', '');
6091
6092 print '<!-- form to add permissions -->'."\n";
6093 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6094 print '<input type="hidden" name="token" value="'.newToken().'">';
6095 print '<input type="hidden" name="action" value="addright">';
6096 print '<input type="hidden" name="tab" value="permissions">';
6097 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
6098 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
6099
6100 print '<div class="div-table-responsive">';
6101 print '<table class="noborder">';
6102
6103 print '<tr class="liste_titre">';
6104 print_liste_field_titre("ID", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
6105 print_liste_field_titre("Object", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
6106 print_liste_field_titre("CRUD", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
6107 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
6108 print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
6109 print "</tr>\n";
6110
6111 //form for add new right
6112 print '<tr class="small">';
6113 print '<td><input type="hidden" readonly name="id" class="width75" value="0"></td>';
6114
6115 print '<td><select class="minwidth100" name="permissionObj" id="permissionObj">';
6116 print '<option value=""></option>';
6117 foreach ($objects as $obj) {
6118 if ($obj != 'myobject') {
6119 print '<option value="'.$obj.'">'.$obj.'</option>';
6120 }
6121 }
6122 print '</select></td>';
6123
6124 print '<td><select class="maxwidth75" name="crud" id="crud">';
6125 print '<option value=""></option>';
6126 foreach ($crud as $key => $val) {
6127 print '<option value="'.$key.'">'.$langs->trans($val).'</option>';
6128 }
6129 print '</td>';
6130
6131 print '<td >';
6132 print '<input type="text" name="label" id="label" class="minwidth200">';
6133 print '</td>';
6134
6135 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
6136 print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
6137 print '</td>';
6138 print '</tr>';
6139
6140 if (count($perms)) {
6141 $i = 0;
6142 foreach ($perms as $perm) {
6143 $i++;
6144
6145 // section for editing right
6146 if ($action == 'edit_right' && $perm[0] == GETPOSTINT('permskey')) {
6147 print '<tr class="oddeven">';
6148 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="modifPerms">';
6149 print '<input type="hidden" name="token" value="'.newToken().'">';
6150 print '<input type="hidden" name="tab" value="permissions">';
6151 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
6152 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
6153 print '<input type="hidden" name="action" value="update_right">';
6154 print '<input type="hidden" name="counter" value="'.$i.'">';
6155
6156 print '<input type="hidden" name="permskey" value="'.$perm[0].'">';
6157
6158 print '<td class="tdsticky tdstickygray">';
6159 print '<input class="width75" type="text" readonly value="'.dol_escape_htmltag($perm[0]).'"/>';
6160 print '</td>';
6161
6162 print '<td>';
6163 print '<select name="crud">';
6164 print '<option value="'.dol_escape_htmltag($perm[5]).'">'.$langs->trans($perm[5]).'</option>';
6165 foreach ($crud as $i => $x) {
6166 if ($perm[5] != $i) {
6167 print '<option value="'.$i.'">'.$langs->trans(ucfirst($x)).'</option>';
6168 }
6169 }
6170 print '</select>';
6171 print '</td>';
6172
6173 print '<td><select name="permissionObj" >';
6174 print '<option value="'.dol_escape_htmltag($perm[4]).'">'.ucfirst($perm[4]).'</option>';
6175 print '</select></td>';
6176
6177 print '<td>';
6178 print '<input type="text" name="label" value="'.dol_escape_htmltag($perm[1]).'">';
6179 print '</td>';
6180
6181 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
6182 print '<input id ="modifyPerm" class="reposition button smallpaddingimp" type="submit" name="modifyright" value="'.$langs->trans("Modify").'"/>';
6183 print '<br>';
6184 print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
6185 print '</td>';
6186
6187 print '</form>';
6188 print '</tr>';
6189 } else {
6190 // $perm can be module->object->crud or module->crud
6191 print '<tr class="oddeven">';
6192
6193 print '<td>';
6194 print dol_escape_htmltag($perm[0]);
6195 print '</td>';
6196
6197 print '<td>';
6198 if (in_array($perm[5], array('lire', 'read', 'creer', 'write', 'effacer', 'delete'))) {
6199 print dol_escape_htmltag(ucfirst($perm[4]));
6200 } else {
6201 print ''; // No particular object
6202 }
6203 print '</td>';
6204
6205 print '<td>';
6206 if (in_array($perm[5], array('lire', 'read', 'creer', 'write', 'effacer', 'delete'))) {
6207 print ucfirst($langs->trans($perm[5]));
6208 } else {
6209 print ucfirst($langs->trans($perm[4]));
6210 }
6211 print '</td>';
6212
6213 print '<td>';
6214 print $langs->trans($perm[1]);
6215 print '</td>';
6216
6217 print '<td class="center minwidth75 tdstickyright tdstickyghostwhite">';
6218 print '<a class="editfielda reposition marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=edit_right&token='.newToken().'&permskey='.urlencode($perm[0]).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj).'">'.img_edit().'</a>';
6219 print '<a class="marginleftonly marginrighttonly paddingright paddingleft" href="'.$_SERVER["PHP_SELF"].'?action=deleteright&token='.newToken().'&permskey='.urlencode((string) ($i)).'&tab='.urlencode((string) ($tab)).'&module='.urlencode((string) ($module)).'&tabobj='.urlencode((string) ($tabobj)).'">'.img_delete().'</a>';
6220
6221 print '</td>';
6222
6223 print '</tr>';
6224 }
6225 }
6226 } else {
6227 print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
6228 }
6229
6230 print '</table>';
6231 print '</div>';
6232
6233 print '</form>';
6234 print '<script>
6235 function updateInputField() {
6236 value1 = $("#crud").val();
6237 value2 = $("#permissionObj").val();
6238
6239 // Vérifie si les deux sélections sont faites
6240 if (value1 && value2) {
6241 switch(value1.toLowerCase()){
6242 case "read":
6243 $("#label").val("Read "+value2+" object of '.ucfirst($module).'")
6244 break;
6245 case "write":
6246 $("#label").val("Create/Update "+value2+" object of '.ucfirst($module).'")
6247 break;
6248 case "delete":
6249 $("#label").val("Delete "+value2+" object of '.ucfirst($module).'")
6250 break;
6251 default:
6252 $("#label").val("")
6253 }
6254 }
6255 }
6256
6257 $("#crud, #permissionObj").change(function(){
6258 console.log("We change selection");
6259 updateInputField();
6260 });
6261
6262 </script>';
6263 } else {
6264 $fullpathoffile = dol_buildpath($file, 0);
6265
6266 $content = file_get_contents($fullpathoffile);
6267
6268 // New module
6269 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6270 print '<input type="hidden" name="token" value="'.newToken().'">';
6271 print '<input type="hidden" name="action" value="savefile">';
6272 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6273 print '<input type="hidden" name="tab" value="'.$tab.'">';
6274 print '<input type="hidden" name="module" value="'.$module.'">';
6275
6276 $posCursor = (empty($find)) ? array() : array('find' => $find);
6277 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6278 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6279 print '<br>';
6280 print '<center>';
6281 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6282 print ' &nbsp; ';
6283 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6284 print '</center>';
6285
6286 print '</form>';
6287 }
6288 }
6289
6290 if ($tab == 'hooks') {
6291 print '<!-- tab=hooks -->'."\n";
6292 if ($action != 'editfile' || empty($file)) {
6293 print '<span class="opacitymedium">'.$langs->trans("HooksDefDesc").'</span><br>';
6294 print '<br>';
6295
6296 print '<table>';
6297
6298 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6299 print '<tr><td>';
6300 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6301 print '</td><td>';
6302 print '<a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=HOOKSCONTEXTS">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6303 print '</td></tr>';
6304
6305 print '<tr><td>';
6306 $pathtohook = strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
6307 print '<span class="fa fa-file"></span> '.$langs->trans("HooksFile").' : ';
6308 if (dol_is_file($dirins.'/'.$pathtohook)) {
6309 print '<strong class="wordbreak">'.$pathtohook.'</strong>';
6310 print '</td>';
6311 print '<td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Edit"), 'edit').'</a> ';
6312 print '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Delete"), 'delete').'</a></td>';
6313 } else {
6314 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6315 print '<a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=inithook&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</td>';
6316 print '<td></td>';
6317 }
6318 print '</tr>';
6319 } else {
6320 $fullpathoffile = dol_buildpath($file, 0);
6321
6322 $content = file_get_contents($fullpathoffile);
6323
6324 // New module
6325 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6326 print '<input type="hidden" name="token" value="'.newToken().'">';
6327 print '<input type="hidden" name="action" value="savefile">';
6328 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6329 print '<input type="hidden" name="tab" value="'.$tab.'">';
6330 print '<input type="hidden" name="module" value="'.$module.'">';
6331
6332 $posCursor = (empty($find)) ? array() : array('find' => $find);
6333 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6334 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6335 print '<br>';
6336 print '<center>';
6337 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6338 print ' &nbsp; ';
6339 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6340 print '</center>';
6341
6342 print '</form>';
6343 }
6344 }
6345
6346 if ($tab == 'triggers') {
6347 print '<!-- tab=triggers -->'."\n";
6348 require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
6349
6350 $interfaces = new Interfaces($db);
6351 $triggers = $interfaces->getTriggersList(array('/'.strtolower($module).'/core/triggers'));
6352
6353 if ($action != 'editfile' || empty($file)) {
6354 print '<span class="opacitymedium">'.$langs->trans("TriggerDefDesc").'</span><br>';
6355 print '<br>';
6356
6357 print '<table>';
6358
6359 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6360 print '<tr><td>';
6361 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6362 print '</td><td>';
6363 print '<a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=module_parts">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6364 print '</td></tr>';
6365
6366 if (!empty($triggers)) {
6367 foreach ($triggers as $trigger) {
6368 $pathtofile = $trigger['relpath'];
6369
6370 print '<tr><td>';
6371 print '<span class="fa fa-file"></span> '.$langs->trans("TriggersFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6372 print '</td><td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a></td>';
6373 print '<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></td>';
6374 print '</tr>';
6375 }
6376 } else {
6377 print '<tr><td>';
6378 print '<span class="fa fa-file"></span> '.$langs->trans("TriggersFile");
6379 print ' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6380 print '<a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=inittrigger&token='.newToken().'&format=php">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a></td>';
6381 print '<td></td>';
6382 print '</tr>';
6383 }
6384
6385 print '</table>';
6386 } else {
6387 $fullpathoffile = dol_buildpath($file, 0);
6388
6389 $content = file_get_contents($fullpathoffile);
6390
6391 // New module
6392 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6393 print '<input type="hidden" name="token" value="'.newToken().'">';
6394 print '<input type="hidden" name="action" value="savefile">';
6395 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6396 print '<input type="hidden" name="tab" value="'.$tab.'">';
6397 print '<input type="hidden" name="module" value="'.$module.'">';
6398
6399 $posCursor = (empty($find)) ? array() : array('find' => $find);
6400 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6401 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6402 print '<br>';
6403 print '<center>';
6404 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6405 print ' &nbsp; ';
6406 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6407 print '</center>';
6408
6409 print '</form>';
6410 }
6411 }
6412
6413 if ($tab == 'css') {
6414 print '<!-- tab=css -->'."\n";
6415 if ($action != 'editfile' || empty($file)) {
6416 print '<span class="opacitymedium">'.$langs->trans("CSSDesc").'</span><br>';
6417 print '<br>';
6418
6419 print '<table>';
6420
6421 print '<tr><td>';
6422 $pathtohook = strtolower($module).'/css/'.strtolower($module).'.css.php';
6423 print '<span class="fa fa-file"></span> '.$langs->trans("CSSFile").' : ';
6424 if (dol_is_file($dirins.'/'.$pathtohook)) {
6425 print '<strong class="wordbreak">'.$pathtohook.'</strong>';
6426 print '</td><td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Edit"), 'edit').'</a></td>';
6427 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&format='.$format.'&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Delete"), 'delete').'</a></td>';
6428 } else {
6429 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6430 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initcss&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a></td>';
6431 }
6432 print '</tr>';
6433 } else {
6434 $fullpathoffile = dol_buildpath($file, 0);
6435
6436 $content = file_get_contents($fullpathoffile);
6437
6438 // New module
6439 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6440 print '<input type="hidden" name="token" value="'.newToken().'">';
6441 print '<input type="hidden" name="action" value="savefile">';
6442 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6443 print '<input type="hidden" name="tab" value="'.$tab.'">';
6444 print '<input type="hidden" name="module" value="'.$module.'">';
6445
6446 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6447 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6448 print '<br>';
6449 print '<center>';
6450 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6451 print ' &nbsp; ';
6452 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6453 print '</center>';
6454
6455 print '</form>';
6456 }
6457 }
6458
6459 if ($tab == 'js') {
6460 print '<!-- tab=js -->'."\n";
6461 if ($action != 'editfile' || empty($file)) {
6462 print '<span class="opacitymedium">'.$langs->trans("JSDesc").'</span><br>';
6463 print '<br>';
6464
6465 print '<table>';
6466
6467 print '<tr><td>';
6468 $pathtohook = strtolower($module).'/js/'.strtolower($module).'.js.php';
6469 print '<span class="fa fa-file"></span> '.$langs->trans("JSFile").' : ';
6470 if (dol_is_file($dirins.'/'.$pathtohook)) {
6471 print '<strong class="wordbreak">'.$pathtohook.'</strong>';
6472 print '</td><td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Edit"), 'edit').'</a></td>';
6473 print '</td><td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($pathtohook).'">'.img_picto($langs->trans("Delete"), 'delete').'</a></td>';
6474 } else {
6475 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6476 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initjs&token='.newToken().'&format=php&file='.urlencode($pathtohook).'">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a></td>';
6477 }
6478 print '</tr>';
6479 } else {
6480 $fullpathoffile = dol_buildpath($file, 0);
6481
6482 $content = file_get_contents($fullpathoffile);
6483
6484 // New module
6485 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6486 print '<input type="hidden" name="token" value="'.newToken().'">';
6487 print '<input type="hidden" name="action" value="savefile">';
6488 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6489 print '<input type="hidden" name="tab" value="'.$tab.'">';
6490 print '<input type="hidden" name="module" value="'.$module.'">';
6491
6492 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6493 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6494 print '<br>';
6495 print '<center>';
6496 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6497 print ' &nbsp; ';
6498 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6499 print '</center>';
6500
6501 print '</form>';
6502 }
6503 }
6504
6505 if ($tab == 'widgets') {
6506 print '<!-- tab=widgets -->'."\n";
6507 require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
6508
6509 $widgets = ModeleBoxes::getWidgetsList(array('/'.strtolower($module).'/core/boxes'));
6510
6511 if ($action != 'editfile' || empty($file)) {
6512 print '<span class="opacitymedium">'.$langs->trans("WidgetDesc").'</span><br>';
6513 print '<br>';
6514
6515 print '<table>';
6516 if (!empty($widgets)) {
6517 foreach ($widgets as $widget) {
6518 $pathtofile = $widget['relpath'];
6519
6520 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("WidgetFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6521 print '</td><td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6522 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></td>';
6523 print '</tr>';
6524 }
6525 } else {
6526 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("WidgetFile").' : <span class="opacitymedium">'.$langs->trans("NoWidget").'</span>';
6527 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initwidget&token='.newToken().'&format=php">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
6528 print '</td></tr>';
6529 }
6530 print '</table>';
6531 } else {
6532 $fullpathoffile = dol_buildpath($file, 0);
6533
6534 $content = file_get_contents($fullpathoffile);
6535
6536 // New module
6537 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6538 print '<input type="hidden" name="token" value="'.newToken().'">';
6539 print '<input type="hidden" name="action" value="savefile">';
6540 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6541 print '<input type="hidden" name="tab" value="'.$tab.'">';
6542 print '<input type="hidden" name="module" value="'.$module.'">';
6543
6544 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6545 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6546 print '<br>';
6547 print '<center>';
6548 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6549 print ' &nbsp; ';
6550 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6551 print '</center>';
6552
6553 print '</form>';
6554 }
6555 }
6556
6557 if ($tab == 'emailings') {
6558 print '<!-- tab=emailings -->'."\n";
6559 require_once DOL_DOCUMENT_ROOT.'/core/modules/mailings/modules_mailings.php';
6560
6561 $emailingselectors = MailingTargets::getEmailingSelectorsList(array('/'.strtolower($module).'/core/modules/mailings'));
6562
6563 if ($action != 'editfile' || empty($file)) {
6564 print '<span class="opacitymedium">'.$langs->trans("EmailingSelectorDesc").'</span><br>';
6565 print '<br>';
6566
6567 print '<table>';
6568 if (!empty($emailingselectors)) {
6569 foreach ($emailingselectors as $emailingselector) {
6570 $pathtofile = $emailingselector['relpath'];
6571
6572 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("EmailingSelectorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6573 print '</td><td><a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6574 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></td>';
6575 print '</tr>';
6576 }
6577 } else {
6578 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("EmailingSelectorFile").' : <span class="opacitymedium">'.$langs->trans("NoEmailingSelector").'</span>';
6579 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initemailing&token='.newToken().'&format=php">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
6580 print '</td></tr>';
6581 }
6582 print '</table>';
6583 } else {
6584 $fullpathoffile = dol_buildpath($file, 0);
6585
6586 $content = file_get_contents($fullpathoffile);
6587
6588 // New module
6589 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6590 print '<input type="hidden" name="token" value="'.newToken().'">';
6591 print '<input type="hidden" name="action" value="savefile">';
6592 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6593 print '<input type="hidden" name="tab" value="'.$tab.'">';
6594 print '<input type="hidden" name="module" value="'.$module.'">';
6595
6596 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6597 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6598 print '<br>';
6599 print '<center>';
6600 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6601 print ' &nbsp; ';
6602 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6603 print '</center>';
6604
6605 print '</form>';
6606 }
6607 }
6608
6609 if ($tab == 'exportimport') {
6610 print '<!-- tab=exportimport -->'."\n";
6611 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6612
6613 $exportlist = $moduleobj->export_label;
6614 $importlist = $moduleobj->import_label;
6615
6616 if ($action != 'editfile' || empty($file)) {
6617 print '<span class="opacitymedium">'.$langs->transnoentities('ImportExportProfiles').'</span><br>';
6618 print '<br>';
6619
6620 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' ('.$langs->trans("ExportsArea").') : <strong class="wordbreak">'.$pathtofile.'</strong>';
6621 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=EXPORT">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6622 print '<br>';
6623 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' ('.$langs->trans("ImportArea").') : <strong class="wordbreak">'.$pathtofile.'</strong>';
6624 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=IMPORT">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6625 print '<br>';
6626 } else {
6627 $fullpathoffile = dol_buildpath($file, 0);
6628
6629 $content = file_get_contents($fullpathoffile);
6630
6631 // New module
6632 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6633 print '<input type="hidden" name="token" value="'.newToken().'">';
6634 print '<input type="hidden" name="action" value="savefile">';
6635 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6636 print '<input type="hidden" name="tab" value="'.$tab.'">';
6637 print '<input type="hidden" name="module" value="'.$module.'">';
6638
6639 $posCursor = (empty($find)) ? array() : array('find' => $find);
6640 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6641 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6642 print '<br>';
6643 print '<center>';
6644 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6645 print ' &nbsp; ';
6646 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6647 print '</center>';
6648
6649 print '</form>';
6650 }
6651 }
6652
6653 if ($tab == 'cli') {
6654 print '<!-- tab=cli -->'."\n";
6655 $clifiles = array();
6656 $i = 0;
6657
6658 $dircli = array('/'.strtolower($module).'/scripts');
6659
6660 foreach ($dircli as $reldir) {
6661 $dir = dol_buildpath($reldir, 0);
6662 $newdir = dol_osencode($dir);
6663
6664 // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
6665 if (!is_dir($newdir)) {
6666 continue;
6667 }
6668
6669 $handle = opendir($newdir);
6670
6671 if (is_resource($handle)) {
6672 while (($tmpfile = readdir($handle)) !== false) {
6673 if (is_readable($newdir.'/'.$tmpfile) && preg_match('/^(.+)\.php/', $tmpfile, $reg)) {
6674 if (preg_match('/\.back$/', $tmpfile)) {
6675 continue;
6676 }
6677
6678 $clifiles[$i]['relpath'] = preg_replace('/^\//', '', $reldir).'/'.$tmpfile;
6679
6680 $i++;
6681 }
6682 }
6683 closedir($handle);
6684 }
6685 }
6686
6687 if ($action != 'editfile' || empty($file)) {
6688 print '<span class="opacitymedium">'.$langs->trans("CLIDesc").'</span><br>';
6689 print '<br>';
6690
6691 print '<table>';
6692 if (!empty($clifiles)) {
6693 foreach ($clifiles as $clifile) {
6694 $pathtofile = $clifile['relpath'];
6695
6696 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("CLIFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6697 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).'">'.img_picto($langs->trans("Edit"), 'edit').'</a></td>';
6698 print '<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></td>';
6699 print '</tr>';
6700 }
6701 } else {
6702 print '<tr><td><span class="fa fa-file"></span> '.$langs->trans("CLIFile").' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6703 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initcli&token='.newToken().'&format=php">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a>';
6704 print '</td></tr>';
6705 }
6706 print '</table>';
6707 } else {
6708 $fullpathoffile = dol_buildpath($file, 0);
6709
6710 $content = file_get_contents($fullpathoffile);
6711
6712 // New module
6713 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6714 print '<input type="hidden" name="token" value="'.newToken().'">';
6715 print '<input type="hidden" name="action" value="savefile">';
6716 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6717 print '<input type="hidden" name="tab" value="'.$tab.'">';
6718 print '<input type="hidden" name="module" value="'.$module.'">';
6719
6720 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6721 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6722 print '<br>';
6723 print '<center>';
6724 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6725 print ' &nbsp; ';
6726 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6727 print '</center>';
6728
6729 print '</form>';
6730 }
6731 }
6732
6733 if ($tab == 'cron') {
6734 print '<!-- tab=cron -->'."\n";
6735 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6736
6737 $cronjobs = $moduleobj->cronjobs;
6738
6739 if ($action != 'editfile' || empty($file)) {
6740 print '<span class="opacitymedium">'.str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/cron/list.php">'.$langs->transnoentities('CronList').'</a>', $langs->trans("CronJobDefDesc", '{s1}')).'</span><br>';
6741 print '<br>';
6742
6743 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6744 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&token='.newToken().'&format=php&file='.urlencode($pathtofile).'&find=CRON">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
6745 print '<br>';
6746
6747 print '<br>';
6748 print load_fiche_titre($langs->trans("CronJobProfiles"), '', '');
6749
6750 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6751 print '<input type="hidden" name="token" value="'.newToken().'">';
6752 print '<input type="hidden" name="action" value="addproperty">';
6753 print '<input type="hidden" name="tab" value="objects">';
6754 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
6755 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
6756
6757 print '<div class="div-table-responsive">';
6758 print '<table class="noborder">';
6759
6760 print '<tr class="liste_titre">';
6761 print_liste_field_titre("CronLabel", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
6762 print_liste_field_titre("CronTask", '', '', "", $param, '', $sortfield, $sortorder);
6763 print_liste_field_titre("CronFrequency", '', "", "", $param, '', $sortfield, $sortorder);
6764 print_liste_field_titre("StatusAtInstall", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
6765 print_liste_field_titre("Comment", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
6766 print "</tr>\n";
6767
6768 if (count($cronjobs)) {
6769 foreach ($cronjobs as $cron) {
6770 print '<tr class="oddeven">';
6771
6772 print '<td>';
6773 print $cron['label'];
6774 print '</td>';
6775
6776 print '<td>';
6777 $texttoshow = '';
6778 if ($cron['jobtype'] == 'method') {
6779 $text = $langs->trans("CronClass");
6780 $texttoshow = $langs->trans('CronModule').': '.$module.'<br>';
6781 $texttoshow .= $langs->trans('CronClass').': '.$cron['class'].'<br>';
6782 $texttoshow .= $langs->trans('CronObject').': '.$cron['objectname'].'<br>';
6783 $texttoshow .= $langs->trans('CronMethod').': '.$cron['method'];
6784 $texttoshow .= '<br>'.$langs->trans('CronArgs').': '.$cron['parameters'];
6785 $texttoshow .= '<br>'.$langs->trans('Comment').': '.$langs->trans($cron['comment']);
6786 } elseif ($cron['jobtype'] == 'command') {
6787 $text = $langs->trans('CronCommand');
6788 $texttoshow = $langs->trans('CronCommand').': '.dol_trunc($cron['command']);
6789 $texttoshow .= '<br>'.$langs->trans('CronArgs').': '.$cron['parameters'];
6790 $texttoshow .= '<br>'.$langs->trans('Comment').': '.$langs->trans($cron['comment']);
6791 }
6792 print $form->textwithpicto($text, $texttoshow, 1);
6793 print '</td>';
6794
6795 print '<td>';
6796 if ($cron['unitfrequency'] == "60") {
6797 print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Minutes');
6798 }
6799 if ($cron['unitfrequency'] == "3600") {
6800 print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Hours');
6801 }
6802 if ($cron['unitfrequency'] == "86400") {
6803 print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Days');
6804 }
6805 if ($cron['unitfrequency'] == "604800") {
6806 print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Weeks');
6807 }
6808 print '</td>';
6809
6810 print '<td>';
6811 print $cron['status'];
6812 print '</td>';
6813
6814 print '<td>';
6815 if (!empty($cron['comment'])) {
6816 print $cron['comment'];
6817 }
6818 print '</td>';
6819
6820 print '</tr>';
6821 }
6822 } else {
6823 print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
6824 }
6825
6826 print '</table>';
6827 print '</div>';
6828
6829 print '</form>';
6830 } else {
6831 $fullpathoffile = dol_buildpath($file, 0);
6832
6833 $content = file_get_contents($fullpathoffile);
6834
6835 // New module
6836 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6837 print '<input type="hidden" name="token" value="'.newToken().'">';
6838 print '<input type="hidden" name="action" value="savefile">';
6839 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6840 print '<input type="hidden" name="tab" value="'.$tab.'">';
6841 print '<input type="hidden" name="module" value="'.$module.'">';
6842
6843 $posCursor = (empty($find)) ? array() : array('find' => $find);
6844 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
6845 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6846 print '<br>';
6847 print '<center>';
6848 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6849 print ' &nbsp; ';
6850 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6851 print '</center>';
6852
6853 print '</form>';
6854 }
6855 }
6856
6857 if ($tab == 'specifications') {
6858 print '<!-- tab=specifications -->'."\n";
6859 $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
6860
6861 if ($action != 'editfile' || empty($file)) {
6862 print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
6863 print '<br>';
6864
6865 print '<table>';
6866 if (is_array($specs) && !empty($specs)) {
6867 foreach ($specs as $spec) {
6868 $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
6869 $format = 'asciidoc';
6870 if (preg_match('/\.md$/i', $spec['name'])) {
6871 $format = 'markdown';
6872 }
6873 print '<tr><td>';
6874 print '<span class="fa fa-file"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
6875 print '</td><td><a class="editfielda paddingleft paddingright" 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></td>';
6876 print '<td><a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&format='.$format.'&file='.urlencode($pathtofile).'">'.img_picto($langs->trans("Delete"), 'delete').'</a></td>';
6877 print '</tr>';
6878 }
6879 } else {
6880 print '<tr><td>';
6881 print '<span class="fa fa-file"></span> '.$langs->trans("SpecificationFile").' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6882 print '</td><td><a href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=initdoc&token='.newToken().'&format=php">'.img_picto('Generate', 'generate', 'class="paddingleft"').'</a></td>';
6883 print '</tr>';
6884 }
6885 print '</table>';
6886 } else {
6887 // Use MD or asciidoc
6888
6889 //print $langs->trans("UseAsciiDocFormat").'<br>';
6890
6891 $fullpathoffile = dol_buildpath($file, 0);
6892
6893 $content = file_get_contents($fullpathoffile);
6894
6895 // New module
6896 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
6897 print '<input type="hidden" name="token" value="'.newToken().'">';
6898 print '<input type="hidden" name="action" value="savefile">';
6899 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
6900 print '<input type="hidden" name="tab" value="'.$tab.'">';
6901 print '<input type="hidden" name="module" value="'.$module.'">';
6902
6903 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%');
6904 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
6905 print '<br>';
6906 print '<center>';
6907 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
6908 print ' &nbsp; ';
6909 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
6910 print '</center>';
6911
6912 print '</form>';
6913 }
6914
6915 print '<br><br><br>';
6916
6917 $FILENAMEDOC = $modulelowercase.'.html';
6918 $FILENAMEDOCPDF = $modulelowercase.'.pdf';
6919 $outputfiledoc = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOC;
6920 $outputfiledocurl = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOC;
6921 $outputfiledocrel = $modulelowercase.'/doc/'.$FILENAMEDOC;
6922 $outputfiledocpdf = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOCPDF;
6923 $outputfiledocurlpdf = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOCPDF;
6924 $outputfiledocrelpdf = $modulelowercase.'/doc/'.$FILENAMEDOCPDF;
6925
6926 // HTML
6927 print '<span class="fa fa-file"></span> '.$langs->trans("PathToModuleDocumentation", "HTML").' : ';
6928 if (!dol_is_file($outputfiledoc)) {
6929 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6930 } else {
6931 print '<strong>';
6932 print '<a href="'.$outputfiledocurl.'" target="_blank" rel="noopener noreferrer">';
6933 print $outputfiledoc;
6934 print '</a>';
6935 print '</strong>';
6936 print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfiledoc), 'dayhour').')</span>';
6937 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&format='.$format.'&file='.urlencode($outputfiledocrel).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
6938 }
6939 print '</strong><br>';
6940
6941 // PDF
6942 print '<span class="fa fa-file"></span> '.$langs->trans("PathToModuleDocumentation", "PDF").' : ';
6943 if (!dol_is_file($outputfiledocpdf)) {
6944 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
6945 } else {
6946 print '<strong>';
6947 print '<a href="'.$outputfiledocurlpdf.'" target="_blank" rel="noopener noreferrer">';
6948 print $outputfiledocpdf;
6949 print '</a>';
6950 print '</strong>';
6951 print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfiledocpdf), 'dayhour').')</span>';
6952 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&format='.$format.'&file='.urlencode($outputfiledocrelpdf).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
6953 }
6954 print '</strong><br>';
6955
6956 print '<br>';
6957
6958 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="generatedoc">';
6959 print '<input type="hidden" name="token" value="'.newToken().'">';
6960 print '<input type="hidden" name="action" value="generatedoc">';
6961 print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
6962 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
6963 print '<input type="submit" class="button" name="generatedoc" value="'.$langs->trans("BuildDocumentation").'"';
6964 if (!is_array($specs) || empty($specs)) {
6965 print ' disabled="disabled"';
6966 }
6967 print '>';
6968 print '</form>';
6969 }
6970
6971 if ($tab == 'buildpackage') {
6972 print '<!-- tab=buildpackage -->'."\n";
6973 print '<span class="opacitymedium">'.$langs->trans("BuildPackageDesc").'</span>';
6974 print '<br>';
6975
6976 if (!class_exists('ZipArchive') && !defined('ODTPHP_PATHTOPCLZIP')) {
6977 print img_warning().' '.$langs->trans("ErrNoZipEngine");
6978 print '<br>';
6979 }
6980
6981 $modulelowercase = strtolower($module);
6982
6983 // Zip file to build
6984 $FILENAMEZIP = '';
6985
6986 // Load module
6987 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
6988 dol_include_once($pathtofile);
6989 $class = 'mod'.$module;
6990 $moduleobj = null;
6991 if (class_exists($class)) {
6992 try {
6993 $moduleobj = new $class($db);
6994 '@phan-var-force DolibarrModules $moduleobj';
6996 } catch (Exception $e) {
6997 $error++;
6998 dol_print_error($db, $e->getMessage());
6999 }
7000 }
7001 if ($moduleobj === null) {
7002 $error++;
7003 $langs->load("errors");
7004 dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
7005 exit;
7006 }
7007
7008 $outputfilezip = null;
7009 $arrayversion = explode('.', $moduleobj->version, 3);
7010 if (count($arrayversion)) {
7011 $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : ".".$arrayversion[2]).".zip";
7012 $outputfilezip = dol_buildpath($modulelowercase, 0).'/bin/'.$FILENAMEZIP;
7013 }
7014
7015 print '<br>';
7016
7017 print '<span class="fa fa-file"></span> '.$langs->trans("PathToModulePackage").' : ';
7018 if ($outputfilezip === null || !dol_is_file($outputfilezip)) {
7019 print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
7020 } else {
7021 $relativepath = $modulelowercase.'/bin/'.$FILENAMEZIP;
7022 print '<strong><a href="'.DOL_URL_ROOT.'/document.php?modulepart=packages&file='.urlencode($relativepath).'">'.$outputfilezip.'</a></strong>';
7023 print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfilezip), 'dayhour').')</span>';
7024 print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&file='.urlencode($relativepath).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
7025 }
7026 print '</strong>';
7027
7028 print '<br>';
7029
7030 print '<br>';
7031
7032 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="generatepackage">';
7033 print '<input type="hidden" name="token" value="'.newToken().'">';
7034 print '<input type="hidden" name="action" value="generatepackage">';
7035 print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
7036 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
7037 print '<input type="submit" class="button" name="generatepackage" value="'.$langs->trans("BuildPackage").'">';
7038 print '</form>';
7039 }
7040
7041 if ($tab == 'tabs') {
7042 $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
7043
7044 $tabs = $moduleobj->tabs;
7045
7046 if ($action != 'editfile' || empty($file)) {
7047 print '<span class="opacitymedium">';
7048 $htmlhelp = $langs->trans("TabsDefDescTooltip", '{s1}');
7049 $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/menus/index.php">'.$langs->trans('Setup').' - '.$langs->trans('Tabs').'</a>', $htmlhelp);
7050 print $form->textwithpicto($langs->trans("TabsDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
7051 print '</span>';
7052 print '<br>';
7053
7054 print '<span class="fa fa-file"></span> '.$langs->trans("DescriptorFile").' : <strong>'.$pathtofile.'</strong>';
7055 print ' <a class="editfielda paddingleft paddingright" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=editfile&format=php&file='.urlencode($pathtofile).'&find=TABS">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
7056 print '<br>';
7057
7058 print '<br>';
7059 print load_fiche_titre($langs->trans("ListOfTabsEntries"), '', '');
7060
7061 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
7062 print '<input type="hidden" name="token" value="'.newToken().'">';
7063 print '<input type="hidden" name="action" value="addproperty">';
7064 print '<input type="hidden" name="tab" value="objects">';
7065 print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
7066 print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
7067
7068 print '<div class="div-table-responsive">';
7069 print '<table class="noborder small">';
7070
7071 print '<tr class="liste_titre">';
7072 print_liste_field_titre("ObjectType", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7073 print_liste_field_titre("Tab", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7074 print_liste_field_titre("Title", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7075 print_liste_field_titre("LangFile", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7076 print_liste_field_titre("Condition", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7077 print_liste_field_titre("Path", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
7078 print "</tr>\n";
7079
7080 if (count($tabs)) {
7081 foreach ($tabs as $tab) {
7082 $parts = explode(':', $tab['data']);
7083
7084 $objectType = $parts[0];
7085 $tabName = $parts[1];
7086 $tabTitle = isset($parts[2]) ? $parts[2] : '';
7087 $langFile = isset($parts[3]) ? $parts[3] : '';
7088 $condition = isset($parts[4]) ? $parts[4] : '';
7089 $path = isset($parts[5]) ? $parts[5] : '';
7090
7091 // If we want to remove the tab, then the format is 'objecttype:tabname:optionalcondition'
7092 // See: https://wiki.dolibarr.org/index.php?title=Tabs_system#To_remove_an_existing_tab
7093 if ($tabName[0] === '-') {
7094 $tabTitle = '';
7095 $condition = isset($parts[2]) ? $parts[2] : '';
7096 }
7097
7098 print '<tr class="oddeven">';
7099
7100 print '<td>';
7101 print dol_escape_htmltag($parts[0]);
7102 print '</td>';
7103
7104 print '<td>';
7105 if ($tabName[0] === "+") {
7106 print '<span class="badge badge-status4 badge-status">' . dol_escape_htmltag($tabName) . '</span>';
7107 } else {
7108 print '<span class="badge badge-status8 badge-status">' . dol_escape_htmltag($tabName) . '</span>';
7109 }
7110 print '</td>';
7111
7112 print '<td>';
7113 print dol_escape_htmltag($tabTitle);
7114 print '</td>';
7115
7116 print '<td>';
7117 print dol_escape_htmltag($langFile);
7118 print '</td>';
7119
7120 print '<td>';
7121 print dol_escape_htmltag($condition);
7122 print '</td>';
7123
7124 print '<td>';
7125 print dol_escape_htmltag($path);
7126 print '</td>';
7127
7128 print '</tr>';
7129 }
7130 } else {
7131 print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
7132 }
7133
7134 print '</table>';
7135 print '</div>';
7136
7137 print '</form>';
7138 } else {
7139 $fullpathoffile = dol_buildpath($file, 0);
7140
7141 $content = file_get_contents($fullpathoffile);
7142
7143 // New module
7144 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
7145 print '<input type="hidden" name="token" value="'.newToken().'">';
7146 print '<input type="hidden" name="action" value="savefile">';
7147 print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
7148 print '<input type="hidden" name="tab" value="'.$tab.'">';
7149 print '<input type="hidden" name="module" value="'.$module.'">';
7150
7151 $posCursor = (empty($find)) ? array() : array('find' => $find);
7152 $doleditor = new DolEditor('editfilecontent', $content, '', 300, 'Full', 'In', true, false, 'ace', 0, '99%', 0, $posCursor);
7153 print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ? GETPOST('format', 'aZ09') : 'html'));
7154 print '<br>';
7155 print '<center>';
7156 print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
7157 print ' &nbsp; ';
7158 print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
7159 print '</center>';
7160
7161 print '</form>';
7162 }
7163 }
7164
7165 if ($tab != 'description') {
7166 print dol_get_fiche_end();
7167 }
7168 }
7169}
7170
7171print dol_get_fiche_end(); // End modules
7172
7173
7174// End of page
7175llxFooter();
7176$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:476
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
print $object position
Definition edit.php:206
Class to manage a WYSIWYG editor.
Class to generate html code for admin pages.
Class to manage generation of HTML components Only common components must be here.
Class to manage triggers.
static getEmailingSelectorsList($forcedir=null)
Return list of widget.
static getWidgetsList($forcedirwidget=null)
Return list of widget.
Immutable value object holding all case variants of a module/object pair.
Strict implementation — reports any residual myobject/mymodule token as a warning.
Class to manage utility methods.
global $mysoc
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
removePatternFromFile(string $filePath, string $pattern)
Removes content from a file that matches a given pattern.
dol_filemtime($pathoffile)
Return time of a file.
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null, $excludearchivefiles=0)
Copy a dir to another dir.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dol_is_dir($folder)
Test if filename is a directory.
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask='0', $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
dol_is_dir_empty($dir)
Return if path is empty.
dol_now($mode='gmt')
Return date for now.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='')
Show information in HTML for admin users or standard users.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $jsonclose='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_sanitizePathName($str, $newstr='_', $unaccent=0, $allowdash=0)
Clean a string to use it as a path name.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
getPictoForType($key, $morecss='')
Return the picto for a data type.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
treeview li table
No Email.
a disabled
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
$moduleobj
Definition index.php:3492
getLicenceHeader($user, $langs, $now)
Produce copyright replacement string for user.
Definition index.php:267
foreach( $dirsrootforscan as $tmpdirread) moduleBuilderShutdownFunction()
Add management to catch fatal errors - shutdown handler.
Definition index.php:243
updateDictionaryInFile($module, $file, $dicts)
Updates a dictionary in a module descriptor file.
deletePropsAndPermsFromDoc($file, $objectname)
Delete property and permissions from documentation ascii file if we delete an object.
filterEnabledTabs($requested, $map)
Filter a list of requested tab keys against the known optional tabs map.
createNewDictionnary($modulename, $file, $namedic, $dictionnaires=null)
Create a new dictionary table.
countItemsInDirectory($path, $type=1)
count directories or files in modulebuilder folder
writePermsInAsciiDoc($file, $destfile)
Write all permissions of each object in AsciiDoc format.
reWriteAllMenus($file, $menus, $menuWantTo, $key, $action)
rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir='', $object=null, $moduletype='external')
Save data into a memory area shared by all users, all sessions on server.
writeApiUrlsInDoc($file_api, $file_doc)
Generate Urls and add them to documentation module.
dolGetListOfObjectClasses($destdir)
Get list of existing objects from a directory.
writePropsInAsciiDoc($file, $objectname, $destfile)
Write all properties of the object in AsciiDoc format.
removeObjectFromApiFile($file, $objects, $objectname)
Remove Object variables and methods from API_Module File.
dolReplaceInFilePreservingModuleBuilderMarkers($file, $arrayreplacement)
Apply substitutions to a module descriptor file while preserving the MODULEBUILDER comment markers.
rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir='', $addfieldentry=array(), $delfieldentry='')
Regenerate files .class.php.
reWriteAllPermissions($file, $permissions, $key, $right, $objectname, $module, $action)
Rewriting all permissions after any actions.
checkExistComment($file, $number)
Function to check if comment BEGIN and END exists in modMyModule class.
getModuleBuilderObjectTabs()
Return the map of optional tabs that can be generated for a ModuleBuilder object.
addObjectsToApiFile($srcfile, $file, $objects, $modulename)
Add Object in ModuleApi File.
$conf db user
Active Directory does not allow anonymous connections.
Definition repair.php:134
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.