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