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