dolibarr  19.0.0-dev
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  'searchall'=>GETPOST('propsearchall', 'int'),
1645  'isameasure'=>GETPOST('propisameasure', 'int'),
1646  'comment'=>GETPOST('propcomment', 'alpha'),
1647  'help'=>GETPOST('prophelp', 'alpha'),
1648  'css'=>GETPOST('propcss', 'alpha'), // Can be 'maxwidth500 widthcentpercentminusxx' for example
1649  'cssview'=>GETPOST('propcssview', 'alpha'),
1650  'csslist'=>GETPOST('propcsslist', 'alpha'),
1651  'default'=>GETPOST('propdefault', 'restricthtml'),
1652  'noteditable'=>intval(GETPOST('propnoteditable', 'int')),
1653  'alwayseditable'=>intval(GETPOST('propalwayseditable', 'int')),
1654  'validate' => GETPOST('propvalidate', 'int')
1655  );
1656 
1657 
1658  if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
1659  $addfieldentry['arrayofkeyval'] = json_decode($addfieldentry['arrayofkeyval'], true);
1660  }
1661  }
1662  } else {
1663  $addfieldentry = array();
1664  }
1665 
1666  /*if (GETPOST('regeneratemissing'))
1667  {
1668  setEventMessages($langs->trans("FeatureNotYetAvailable"), null, 'warnings');
1669  $error++;
1670  }*/
1671 
1672  $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1673 
1674  // Edit the class file to write properties
1675  if (!$error) {
1676  $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, $addfieldentry, $moduletype);
1677 
1678  if (is_numeric($object) && $object <= 0) {
1679  $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1680  setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1681  $error++;
1682  }
1683  }
1684 
1685  // Edit sql with new properties
1686  if (!$error) {
1687  $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object, $moduletype);
1688 
1689  if ($result <= 0) {
1690  setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1691  $error++;
1692  }
1693  }
1694 
1695  if (!$error) {
1696  clearstatcache(true);
1697 
1698  setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1699 
1700  setEventMessages($langs->trans('WarningDatabaseIsNotUpdated'), null);
1701 
1702  // Make a redirect to reload all data
1703  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname.'&nocache='.time());
1704 
1705  exit;
1706  }
1707 }
1708 
1709 if ($dirins && $action == 'confirm_deleteproperty' && $propertykey) {
1710  $objectname = $tabobj;
1711 
1712  $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1713  $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1714 
1715  $srcdir = $dirread.'/'.strtolower($module);
1716  $destdir = $dirins.'/'.strtolower($module);
1717  dol_mkdir($destdir);
1718 
1719  // Edit the class file to write properties
1720  if (!$error) {
1721  $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, array(), $propertykey);
1722 
1723  if (is_numeric($object) && $object <= 0) {
1724  $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1725  setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1726  $error++;
1727  }
1728  }
1729 
1730  // Edit sql with new properties
1731  if (!$error) {
1732  $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object);
1733 
1734  if ($result <= 0) {
1735  setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1736  $error++;
1737  }
1738  }
1739 
1740  if (!$error) {
1741  setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1742 
1743  clearstatcache(true);
1744 
1745  // Make a redirect to reload all data
1746  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname);
1747 
1748  exit;
1749  }
1750 }
1751 
1752 if ($dirins && $action == 'confirm_deletemodule') {
1753  if (preg_match('/[^a-z0-9_]/i', $module)) {
1754  $error++;
1755  setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1756  }
1757 
1758  if (!$error) {
1759  $modulelowercase = strtolower($module);
1760 
1761  // Dir for module
1762  $dir = $dirins.'/'.$modulelowercase;
1763 
1764  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1765 
1766  // Dir for module
1767  $dir = dol_buildpath($modulelowercase, 0);
1768 
1769  // Zip file to build
1770  $FILENAMEZIP = '';
1771 
1772  // Load module
1773  dol_include_once($pathtofile);
1774  $class = 'mod'.$module;
1775 
1776  if (class_exists($class)) {
1777  try {
1778  $moduleobj = new $class($db);
1779  } catch (Exception $e) {
1780  $error++;
1781  dol_print_error($db, $e->getMessage());
1782  }
1783  } else {
1784  $error++;
1785  $langs->load("errors");
1786  dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1787  exit;
1788  }
1789 
1790  $moduleobj->remove();
1791 
1792  $result = dol_delete_dir_recursive($dir);
1793 
1794  if ($result > 0) {
1795  setEventMessages($langs->trans("DirWasRemoved", $modulelowercase), null);
1796 
1797  clearstatcache(true);
1798  if (function_exists('opcache_invalidate')) {
1799  opcache_reset(); // remove the include cache hell !
1800  }
1801 
1802  header("Location: ".$_SERVER["PHP_SELF"].'?module=deletemodule');
1803  exit;
1804  } else {
1805  setEventMessages($langs->trans("PurgeNothingToDelete"), null, 'warnings');
1806  }
1807  }
1808 
1809  $action = '';
1810  $module = 'deletemodule';
1811 }
1812 
1813 if ($dirins && $action == 'confirm_deleteobject' && $objectname) {
1814  if (preg_match('/[^a-z0-9_]/i', $objectname)) {
1815  $error++;
1816  setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1817  }
1818 
1819  if (!$error) {
1820  $modulelowercase = strtolower($module);
1821  $objectlowercase = strtolower($objectname);
1822 
1823  // Dir for module
1824  $dir = $dirins.'/'.$modulelowercase;
1825 
1826  // Delete some files
1827  $filetodelete = array(
1828  'myobject_card.php'=>strtolower($objectname).'_card.php',
1829  'myobject_note.php'=>strtolower($objectname).'_note.php',
1830  'myobject_contact.php'=>strtolower($objectname).'_contact.php',
1831  'myobject_document.php'=>strtolower($objectname).'_document.php',
1832  'myobject_agenda.php'=>strtolower($objectname).'_agenda.php',
1833  'myobject_list.php'=>strtolower($objectname).'_list.php',
1834  'admin/myobject_extrafields.php'=>'admin/'.strtolower($objectname).'_extrafields.php',
1835  'lib/mymodule_myobject.lib.php'=>'lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php',
1836  'test/phpunit/MyObjectTest.php'=>'test/phpunit/'.strtolower($objectname).'Test.php',
1837  'sql/llx_mymodule_myobject.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql',
1838  'sql/llx_mymodule_myobject_extrafields.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql',
1839  'sql/llx_mymodule_myobject.key.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql',
1840  'sql/llx_mymodule_myobject_extrafields.key.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql',
1841  'scripts/myobject.php'=>'scripts/'.strtolower($objectname).'.php',
1842  'class/myobject.class.php'=>'class/'.strtolower($objectname).'.class.php',
1843  'class/api_myobject.class.php'=>'class/api_'.strtolower($module).'.class.php',
1844  'core/modules/mymodule/mod_myobject_advanced.php'=>'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_advanced.php',
1845  'core/modules/mymodule/mod_myobject_standard.php'=>'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_standard.php',
1846  'core/modules/mymodule/modules_myobject.php'=>'core/modules/'.strtolower($module).'/modules_'.strtolower($objectname).'.php',
1847  'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php'=>'core/modules/'.strtolower($module).'/doc/doc_generic_'.strtolower($objectname).'_odt.modules.php',
1848  'core/modules/mymodule/doc/pdf_standard_myobject.modules.php'=>'core/modules/'.strtolower($module).'/doc/pdf_standard_'.strtolower($objectname).'.modules.php'
1849  );
1850 
1851  //menu for the object selected
1852  // load class and check if menu,permission,documentation exist for this object
1853  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1854  dol_include_once($pathtofile);
1855  $class = 'mod'.$module;
1856  if (class_exists($class)) {
1857  try {
1858  $moduleobj = new $class($db);
1859  } catch (Exception $e) {
1860  $error++;
1861  dol_print_error($db, $e->getMessage());
1862  }
1863  }
1864  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1865 
1866  // delete menus linked to the object
1867  $menus = $moduleobj->menu;
1868  reWriteAllMenus($moduledescriptorfile, $menus, $objectname, null, -1);
1869 
1870  // regenerate permissions and delete them
1871  $permissions = $moduleobj->rights;
1872  reWriteAllPermissions($moduledescriptorfile, $permissions, null, null, $objectname, '', -1);
1873 
1874  // check if documentation has been generated
1875  $file_doc = $dirins.'/'.strtolower($module).'/doc/Documentation.asciidoc';
1876  deletePropsFromDoc($file_doc, $objectname);
1877 
1878  clearstatcache(true);
1879  if (function_exists('opcache_invalidate')) {
1880  opcache_reset(); // remove the include cache hell !
1881  }
1882  $resultko = 0;
1883  foreach ($filetodelete as $tmpfiletodelete) {
1884  $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete, 0, 0, 1);
1885  $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete.'.back', 0, 0, 1);
1886  if (!$resulttmp) {
1887  $resultko++;
1888  }
1889  }
1890 
1891  if ($resultko == 0) {
1892  setEventMessages($langs->trans("FilesDeleted"), null);
1893  } else {
1894  setEventMessages($langs->trans("ErrorSomeFilesCouldNotBeDeleted"), null, 'warnings');
1895  }
1896  }
1897 
1898  $action = '';
1899  $tabobj = 'deleteobject';
1900 
1901  // check if module is enabled
1902  if (isModEnabled(strtolower($module))) {
1903  $result = unActivateModule(strtolower($module));
1904  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
1905  if ($result) {
1906  setEventMessages($result, null, 'errors');
1907  }
1908  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
1909  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module);
1910  exit;
1911  }
1912 }
1913 
1914 if ($dirins && $action == 'generatedoc') {
1915  $modulelowercase = strtolower($module);
1916 
1917  // Dir for module
1918  $dirofmodule = dol_buildpath($modulelowercase, 0).'/doc';
1919 
1920  $FILENAMEDOC = strtolower($module).'.html';
1921 
1922  $util = new Utils($db);
1923  $result = $util->generateDoc($module);
1924 
1925  if ($result > 0) {
1926  setEventMessages($langs->trans("DocFileGeneratedInto", $dirofmodule), null);
1927  } else {
1928  setEventMessages($util->error, $util->errors, 'errors');
1929  }
1930 }
1931 
1932 if ($dirins && $action == 'generatepackage') {
1933  $modulelowercase = strtolower($module);
1934 
1935  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1936 
1937  // Dir for module
1938  $dir = dol_buildpath($modulelowercase, 0);
1939 
1940  // Zip file to build
1941  $FILENAMEZIP = '';
1942 
1943  // Load module
1944  dol_include_once($pathtofile);
1945  $class = 'mod'.$module;
1946 
1947  if (class_exists($class)) {
1948  try {
1949  $moduleobj = new $class($db);
1950  } catch (Exception $e) {
1951  $error++;
1952  dol_print_error($db, $e->getMessage());
1953  }
1954  } else {
1955  $error++;
1956  $langs->load("errors");
1957  dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1958  exit;
1959  }
1960 
1961  $arrayversion = explode('.', $moduleobj->version, 3);
1962  if (count($arrayversion)) {
1963  $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : '.'.$arrayversion[2]).'.zip';
1964 
1965  $dirofmodule = dol_buildpath($modulelowercase, 0).'/bin';
1966  $outputfilezip = $dirofmodule.'/'.$FILENAMEZIP;
1967  if ($dirofmodule) {
1968  if (!dol_is_dir($dirofmodule)) {
1969  dol_mkdir($dirofmodule);
1970  }
1971  // Note: We exclude /bin/ to not include the already generated zip
1972  $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase);
1973  } else {
1974  $result = -1;
1975  }
1976 
1977  if ($result > 0) {
1978  setEventMessages($langs->trans("ZipFileGeneratedInto", $outputfilezip), null);
1979  } else {
1980  $error++;
1981  $langs->load("errors");
1982  setEventMessages($langs->trans("ErrorFailToGenerateFile", $outputfilezip), null, 'errors');
1983  }
1984  } else {
1985  $error++;
1986  $langs->load("errors");
1987  setEventMessages($langs->trans("ErrorCheckVersionIsDefined"), null, 'errors');
1988  }
1989 }
1990 
1991 // Add permission
1992 if ($dirins && $action == 'addright' && !empty($module) && empty($cancel)) {
1993  $error = 0;
1994 
1995  // load class and check if right exist
1996  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1997  dol_include_once($pathtofile);
1998  $class = 'mod'.$module;
1999  if (class_exists($class)) {
2000  try {
2001  $moduleobj = new $class($db);
2002  } catch (Exception $e) {
2003  $error++;
2004  dol_print_error($db, $e->getMessage());
2005  }
2006  }
2007 
2008  // verify informations entred
2009  if (!GETPOST('label', 'alpha')) {
2010  $error++;
2011  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2012  }
2013  if (!GETPOST('permissionObj', 'alpha')) {
2014  $error++;
2015  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2016  }
2017 
2018  $id = GETPOST('id', 'alpha');
2019  $label = GETPOST('label', 'alpha');
2020  $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2021  $crud = GETPOST('crud', 'alpha');
2022 
2023  //check existing object permission
2024  $counter = 0;
2025  $permsForObject =array();
2026  $permissions = $moduleobj->rights;
2027  $allObject = array();
2028 
2029  $countPerms = count($permissions);
2030 
2031  for ($i =0; $i<$countPerms; $i++) {
2032  if ($permissions[$i][4] == $objectForPerms) {
2033  $counter++;
2034  if (count($permsForObject) < 3) {
2035  $permsForObject[] = $permissions[$i];
2036  }
2037  }
2038  $allObject[] = $permissions[$i][4];
2039  }
2040 
2041  // check if label of object already exists
2042  $countPermsObj = count($permsForObject);
2043  for ($j = 0; $j<$countPermsObj; $j++) {
2044  if (in_array($crud, $permsForObject[$j])) {
2045  $error++;
2046  setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($crud), $langs->transnoentities($objectForPerms)), null, 'errors');
2047  }
2048  }
2049 
2050  if (!$error) {
2051  $key = $countPerms + 1;
2052  //prepare right to add
2053  $rightToAdd = [
2054  0=> $id,
2055  1=>$label,
2056  4=>$objectForPerms,
2057  5=>$crud
2058  ];
2059 
2060  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2061  //rewriting all permissions after add a right
2062  reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightToAdd, '', '', 1);
2063  setEventMessages($langs->trans('PermissionAddedSuccesfuly'), null);
2064 
2065  if (isModEnabled(strtolower($module))) {
2066  $result = unActivateModule(strtolower($module));
2067  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2068  if ($result) {
2069  setEventMessages($result, null, 'errors');
2070  }
2071  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2072  }
2073  }
2074 
2075  clearstatcache(true);
2076  if (function_exists('opcache_invalidate')) {
2077  opcache_reset(); // remove the include cache hell !
2078  }
2079 
2080  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2081  exit;
2082 }
2083 
2084 
2085 // Update permission
2086 if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright')&& empty($cancel)) {
2087  $error = 0;
2088  // load class and check if right exist
2089  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2090  dol_include_once($pathtofile);
2091  $class = 'mod'.$module;
2092  if (class_exists($class)) {
2093  try {
2094  $moduleobj = new $class($db);
2095  } catch (Exception $e) {
2096  $error++;
2097  dol_print_error($db, $e->getMessage());
2098  }
2099  }
2100  // verify informations entred
2101  if (!GETPOST('label', 'alpha')) {
2102  $error++;
2103  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
2104  }
2105  if (!GETPOST('permissionObj', 'alpha')) {
2106  $error++;
2107  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rights")), null, 'errors');
2108  }
2109 
2110  $label = GETPOST('label', 'alpha');
2111  $objectForPerms = strtolower(GETPOST('permissionObj', 'alpha'));
2112  $crud = GETPOST('crud', 'alpha');
2113 
2114 
2115  if ($label == "Read objects of $module" && $crud != "read") {
2116  $crud = "read";
2117  $label == "Read objects of $module";
2118  }
2119  if ($label == "Create/Update objects of $module" && $crud != "write") {
2120  $crud = "write";
2121  $label == "Create/Update objects of $module";
2122  }
2123  if ($label == "Delete objects of $module" && $crud != "delete") {
2124  $crud = "delete";
2125  $label == "Delete objects of $module";
2126  }
2127 
2128  $permissions = $moduleobj->rights;
2129  $key =(int) GETPOST('counter')-1;
2130  //get permission want to delete from permissions array
2131  $x1 = $permissions[$key][1];
2132  $x2 = $permissions[$key][4];
2133  $x3 = $permissions[$key][5];
2134  //check existing object permission
2135  $counter = 0;
2136  $permsForObject =array();
2137  $permissions = $moduleobj->rights;
2138  $firstRight = 0;
2139  $existRight = 0;
2140  $allObject = array();
2141 
2142  $countPerms = count($permissions);
2143  for ($i =0; $i<$countPerms; $i++) {
2144  if ($permissions[$i][4] == $objectForPerms) {
2145  $counter++;
2146  if (count($permsForObject) < 3) {
2147  $permsForObject[] = $permissions[$i];
2148  }
2149  }
2150  $allObject[] = $permissions[$i][4];
2151  }
2152 
2153  if ($label != $x1 && $crud != $x3) {
2154  $countPermsObj = count($permsForObject);
2155  for ($j = 0; $j<$countPermsObj; $j++) {
2156  if (in_array($label, $permsForObject[$j])) {
2157  $error++;
2158  setEventMessages($langs->trans("ErrorExistingPermission", $langs->transnoentities($label), $langs->transnoentities($objectForPerms)), null, 'errors');
2159  }
2160  }
2161  }
2162 
2163  if (!$error) {
2164  if (isModEnabled(strtolower($module))) {
2165  $result = unActivateModule(strtolower($module));
2166  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2167  if ($result) {
2168  setEventMessages($result, null, 'errors');
2169  }
2170  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2171  }
2172 
2173  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2174  // rewriting all permissions after update permission needed
2175  reWriteAllPermissions($moduledescriptorfile, $permissions, $key, $rightUpdated, '', '', 2);
2176 
2177  setEventMessages($langs->trans('PermissionUpdatedSuccesfuly'), null);
2178 
2179  clearstatcache(true);
2180  if (function_exists('opcache_invalidate')) {
2181  opcache_reset(); // remove the include cache hell !
2182  }
2183 
2184  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2185  exit;
2186  }
2187 }
2188 // Delete permission
2189 if ($dirins && $action == 'confirm_deleteright' && !empty($module) && GETPOST('permskey', 'int')) {
2190  $error = 0;
2191  // load class and check if right exist
2192  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2193  dol_include_once($pathtofile);
2194  $class = 'mod'.$module;
2195  if (class_exists($class)) {
2196  try {
2197  $moduleobj = new $class($db);
2198  } catch (Exception $e) {
2199  $error++;
2200  dol_print_error($db, $e->getMessage());
2201  }
2202  }
2203 
2204  $permissions = $moduleobj->rights;
2205  $key = (int) GETPOST('permskey', 'int')-1;
2206 
2207  if (!$error) {
2208  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2209 
2210  // rewriting all permissions
2211  reWriteAllPermissions($moduledescriptorfile, $permissions, $key, null, '', '', 0);
2212 
2213  // check if module is enabled
2214  if (isModEnabled(strtolower($module))) {
2215  $result = unActivateModule(strtolower($module));
2216  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2217  if ($result) {
2218  setEventMessages($result, null, 'errors');
2219  }
2220  setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null);
2221  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2222 
2223  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2224  exit;
2225  } else {
2226  setEventMessages($langs->trans('PermissionDeletedSuccesfuly'), null);
2227 
2228  clearstatcache(true);
2229  if (function_exists('opcache_invalidate')) {
2230  opcache_reset(); // remove the include cache hell !
2231  }
2232 
2233  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=permissions&module='.$module);
2234  exit;
2235  }
2236  }
2237 }
2238 // Save file
2239 if ($action == 'savefile' && empty($cancel)) {
2240  $relofcustom = basename($dirins);
2241 
2242  if ($relofcustom) {
2243  // Check that relative path ($file) start with name 'custom'
2244  if (!preg_match('/^'.$relofcustom.'/', $file)) {
2245  $file = $relofcustom.'/'.$file;
2246  }
2247 
2248  $pathoffile = dol_buildpath($file, 0);
2249  $pathoffilebackup = dol_buildpath($file.'.back', 0);
2250 
2251  // Save old version
2252  if (dol_is_file($pathoffile)) {
2253  dol_copy($pathoffile, $pathoffilebackup, 0, 1);
2254  }
2255 
2256  $check = 'restricthtml';
2257  $srclang = dol_mimetype($pathoffile, '', 3);
2258  if ($srclang == 'md') {
2259  $check = 'restricthtml';
2260  }
2261  if ($srclang == 'lang') {
2262  $check = 'restricthtml';
2263  }
2264  if ($srclang == 'php') {
2265  $check = 'none';
2266  }
2267 
2268  $content = GETPOST('editfilecontent', $check);
2269 
2270  // Save file on disk
2271  if ($content) {
2272  dol_delete_file($pathoffile);
2273  $result = file_put_contents($pathoffile, $content);
2274  if ($result) {
2275  dolChmod($pathoffile, $newmask);
2276 
2277  setEventMessages($langs->trans("FileSaved"), null);
2278  } else {
2279  setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
2280  }
2281  } else {
2282  setEventMessages($langs->trans("ContentCantBeEmpty"), null, 'errors');
2283  //$action='editfile';
2284  $error++;
2285  }
2286  }
2287 }
2288 
2289 // Enable module
2290 if ($action == 'set' && $user->admin) {
2291  $param = '';
2292  if ($module) {
2293  $param .= '&module='.urlencode($module);
2294  }
2295  if ($tab) {
2296  $param .= '&tab='.urlencode($tab);
2297  }
2298  if ($tabobj) {
2299  $param .= '&tabobj='.urlencode($tabobj);
2300  }
2301 
2302  $value = GETPOST('value', 'alpha');
2303  $resarray = activateModule($value);
2304  if (!empty($resarray['errors'])) {
2305  setEventMessages('', $resarray['errors'], 'errors');
2306  } else {
2307  //var_dump($resarray);exit;
2308  if ($resarray['nbperms'] > 0) {
2309  $tmpsql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1";
2310  $resqltmp = $db->query($tmpsql);
2311  if ($resqltmp) {
2312  $obj = $db->fetch_object($resqltmp);
2313  //var_dump($obj->nb);exit;
2314  if ($obj && $obj->nb > 1) {
2315  $msg = $langs->trans('ModuleEnabledAdminMustCheckRights');
2316  setEventMessages($msg, null, 'warnings');
2317  }
2318  } else {
2319  dol_print_error($db);
2320  }
2321  }
2322  }
2323  header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2324  exit;
2325 }
2326 
2327 // Disable module
2328 if ($action == 'reset' && $user->admin) {
2329  $param = '';
2330  if ($module) {
2331  $param .= '&module='.urlencode($module);
2332  }
2333  if ($tab) {
2334  $param .= '&tab='.urlencode($tab);
2335  }
2336  if ($tabobj) {
2337  $param .= '&tabobj='.urlencode($tabobj);
2338  }
2339 
2340  $value = GETPOST('value', 'alpha');
2341  $result = unActivateModule($value);
2342  if ($result) {
2343  setEventMessages($result, null, 'errors');
2344  }
2345  header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
2346  exit;
2347 }
2348 
2349 // delete menu
2350 if ($dirins && $action == 'confirm_deletemenu' && GETPOST('menukey', 'int')) {
2351  // check if module is enabled
2352  if (isModEnabled(strtolower($module))) {
2353  $result = unActivateModule(strtolower($module));
2354  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2355  if ($result) {
2356  setEventMessages($result, null, 'errors');
2357  }
2358  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2359  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2360  }
2361  // load class and check if menu exist
2362  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2363  dol_include_once($pathtofile);
2364  $class = 'mod'.$module;
2365  if (class_exists($class)) {
2366  try {
2367  $moduleobj = new $class($db);
2368  } catch (Exception $e) {
2369  $error++;
2370  dol_print_error($db, $e->getMessage());
2371  }
2372  }
2373  // get all objects and convert value to lower case for compare
2374  $dir = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2375  $destdir = $dir.'/'.strtolower($module);
2376  $objects = dolGetListOfObjectClasses($destdir);
2377  $result = array_map('strtolower', $objects);
2378 
2379  $menus = $moduleobj->menu;
2380  $key = (int) GETPOST('menukey', 'int');
2381  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2382 
2383  if ($menus[$key]['fk_menu'] === 'fk_mainmenu='.strtolower($module)) {
2384  if (in_array(strtolower($menus[$key]['leftmenu']), $result)) {
2385  reWriteAllMenus($moduledescriptorfile, $menus, $menus[$key]['leftmenu'], $key, -1);
2386  } else {
2387  reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
2388  }
2389  } else {
2390  reWriteAllMenus($moduledescriptorfile, $menus, null, $key, 0);
2391  }
2392 
2393  clearstatcache(true);
2394  if (function_exists('opcache_invalidate')) {
2395  opcache_reset(); // remove the include cache hell !
2396  }
2397 
2398  setEventMessages($langs->trans('MenuDeletedSuccessfuly'), null);
2399  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2400  exit;
2401 }
2402 
2403 // Add menu in module without initial object
2404 if ($dirins && $action == 'addmenu' && empty($cancel)) {
2405  // check if module is enabled
2406  if (isModEnabled(strtolower($module))) {
2407  $result = unActivateModule(strtolower($module));
2408  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2409  if ($result) {
2410  setEventMessages($result, null, 'errors');
2411  }
2412  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2413  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2414  }
2415  $error = 0;
2416 
2417  // load class and check if right exist
2418  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2419  dol_include_once($pathtofile);
2420  $class = 'mod'.$module;
2421  if (class_exists($class)) {
2422  try {
2423  $moduleobj = new $class($db);
2424  } catch (Exception $e) {
2425  $error++;
2426  dol_print_error($db, $e->getMessage());
2427  }
2428  }
2429  // get all menus
2430  $menus = $moduleobj->menu;
2431 
2432  //verify fields required
2433  if (!GETPOST('type', 'alpha')) {
2434  $error++;
2435  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
2436  }
2437  if (!GETPOST('titre', 'alpha')) {
2438  $error++;
2439  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Title")), null, 'errors');
2440  }
2441  if (!GETPOST('user', 'alpha')) {
2442  $error++;
2443  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("DetailUser")), null, 'errors');
2444  }
2445  if (!GETPOST('url', 'alpha')) {
2446  $error++;
2447  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Url")), null, 'errors');
2448  }
2449  if (!empty(GETPOST('target'))) {
2450  $targets = array('_blank','_self','_parent','_top','');
2451  if (!in_array(GETPOST('target'), $targets)) {
2452  $error++;
2453  setEventMessages($langs->trans("ErrorFieldValue", $langs->transnoentities("target")), null, 'errors');
2454  }
2455  }
2456 
2457 
2458  // check if title or url already exist in menus
2459 
2460  foreach ($menus as $menu) {
2461  if (!empty(GETPOST('url')) && GETPOST('url') == $menu['url']) {
2462  $error++;
2463  setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("url")), null, 'errors');
2464  break;
2465  }
2466  if (strtolower(GETPOST('titre')) == strtolower($menu['titre'])) {
2467  $error++;
2468  setEventMessages($langs->trans("ErrorFieldExist", $langs->transnoentities("titre")), null, 'errors');
2469  break;
2470  }
2471  }
2472 
2473  if (GETPOST('type', 'alpha') == 'left' && !empty(GETPOST('lefmenu', 'alpha'))) {
2474  if (!str_contains(GETPOST('leftmenu'), strtolower($module))) {
2475  $error++;
2476  setEventMessages($langs->trans("WarningFieldsMustContains", $langs->transnoentities("leftmenu")), null, 'errors');
2477  }
2478  }
2479  $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2480  $destdir = $dirins.'/'.strtolower($module);
2481  $objects = dolGetListOfObjectClasses($destdir);
2482 
2483  if (GETPOST('type', 'alpha') == 'left') {
2484  if (empty(GETPOST('leftmenu')) && count($objects) >0) {
2485  $error++;
2486  setEventMessages($langs->trans("ErrorCoherenceMenu", $langs->transnoentities("leftmenu"), $langs->transnoentities("type")), null, 'errors');
2487  }
2488  }
2489  if (GETPOST('type', 'alpha') == 'top') {
2490  $error++;
2491  setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
2492  }
2493 
2494  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2495  if (!$error) {
2496  //stock forms in array
2497  $menuToAdd = array(
2498  'fk_menu' => GETPOST('fk_menu', 'alpha'),
2499  'type' => GETPOST('type', 'alpha'),
2500  'titre' => ucfirst(GETPOST('titre', 'alpha')),
2501  'prefix' => '',
2502  'mainmenu' => GETPOST('mainmenu', 'alpha'),
2503  'leftmenu' => GETPOST('leftmenu', 'alpha'),
2504  'url' => GETPOST('url', 'alpha'),
2505  'langs' => strtolower($module)."@".strtolower($module),
2506  'position' => '',
2507  'enabled' => GETPOST('enabled', 'alpha'),
2508  'perms' => GETPOST('perms', 'alpha'),
2509  'target' => GETPOST('target', 'alpha'),
2510  'user' => GETPOST('user', 'alpha'),
2511  );
2512  if (GETPOST('type') == 'left') {
2513  unset($menuToAdd['prefix']);
2514  if (empty(GETPOST('fk_menu'))) {
2515  $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha');
2516  } else {
2517  $menuToAdd['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu', 'alpha').',fk_leftmenu='.GETPOST('fk_menu');
2518  }
2519  }
2520  if (GETPOST('enabled') == '1') {
2521  $menuToAdd['enabled'] = "\$conf->".strtolower($module)."->enabled";
2522  } else {
2523  $menuToAdd['enabled'] = "0";
2524  }
2525  $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuToAdd, null, 1);
2526 
2527  clearstatcache(true);
2528  if (function_exists('opcache_invalidate')) {
2529  opcache_reset();
2530  }
2531  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2532  setEventMessages($langs->trans('MenuAddedSuccesfuly'), null);
2533  exit;
2534  }
2535 }
2536 
2537 // modify a menu
2538 if ($dirins && $action == "modify_menu" && GETPOST('menukey', 'int')) {
2539  if (empty($cancel)) {
2540  if (isModEnabled(strtolower($module))) {
2541  $result = unActivateModule(strtolower($module));
2542  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity);
2543  if ($result) {
2544  setEventMessages($result, null, 'errors');
2545  }
2546  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2547  setEventMessages($langs->trans('WarningModuleNeedRefrech', $langs->transnoentities($module)), null, 'warnings');
2548  }
2549  $error = 0;
2550  // for loading class and the menu wants to modify
2551  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2552  dol_include_once($pathtofile);
2553  $class = 'mod'.$module;
2554  if (class_exists($class)) {
2555  try {
2556  $moduleobj = new $class($db);
2557  } catch (Exception $e) {
2558  $error++;
2559  dol_print_error($db, $e->getMessage());
2560  }
2561  }
2562  $menus = $moduleobj->menu;
2563  $key = (int) GETPOST('menukey', 'int') - 1;
2564 
2565  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
2566  //stock forms in array
2567  $menuModify = array(
2568  'fk_menu' => GETPOST('fk_menu', 'alpha'),
2569  'type' => GETPOST('type', 'alpha'),
2570  'titre' => ucfirst(GETPOST('titre', 'alpha')),
2571  'mainmenu' => GETPOST('mainmenu', 'alpha'),
2572  'leftmenu' => $menus[$key]['leftmenu'],
2573  'url' => GETPOST('url', 'alpha'),
2574  'langs' => strtolower($module)."@".strtolower($module),
2575  'position' => '',
2576  'enabled' => GETPOST('enabled', 'alpha'),
2577  'perms' => GETPOST('perms', 'alpha'),
2578  'target' => GETPOST('target', 'alpha'),
2579  'user' => GETPOST('user', 'alpha'),
2580  );
2581  if (!empty(GETPOST('fk_menu')) && GETPOST('fk_menu') != $menus[$key]['fk_menu']) {
2582  $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu').',fk_leftmenu='.GETPOST('fk_menu');
2583  } elseif (GETPOST('fk_menu') == $menus[$key]['fk_menu']) {
2584  $menuModify['fk_menu'] = $menus[$key]['fk_menu'];
2585  } else {
2586  $menuModify['fk_menu'] = 'fk_mainmenu='.GETPOST('mainmenu');
2587  }
2588  if (GETPOST('enabled') != '0') {
2589  $menuModify['enabled'] = "\$conf->".strtolower($module)."->enabled";
2590  } else {
2591  $menuModify['enabled'] = "0";
2592  }
2593 
2594  if (GETPOST('type', 'alpha') == 'top') {
2595  $error++;
2596  setEventMessages($langs->trans("ErrorTypeMenu", $langs->transnoentities("type")), null, 'errors');
2597  }
2598  if (!$error) {
2599  //update menu
2600  $result = reWriteAllMenus($moduledescriptorfile, $menus, $menuModify, $key, 2);
2601 
2602  clearstatcache(true);
2603  if (function_exists('opcache_invalidate')) {
2604  opcache_reset();
2605  }
2606  if ($result < 0) {
2607  setEventMessages($langs->trans('ErrorMenuExistValue'), null, 'errors');
2608  header("Location: ".$_SERVER["PHP_SELF"].'?action=editmenu&token='.newToken().'&menukey='.urlencode($key+1).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.($key+1));
2609  exit;
2610  }
2611  setEventMessages($langs->trans('MenuUpdatedSuccessfuly'), null);
2612  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=menus&module='.$module);
2613  exit;
2614  }
2615  } else {
2616  $_POST['type'] = '';
2617  $_POST['titre'] = '';
2618  $_POST['fk_menu'] = '';
2619  $_POST['leftmenu'] = '';
2620  $_POST['url'] = '';
2621  }
2622 }
2623 
2624 /*
2625  * View
2626  */
2627 
2628 $form = new Form($db);
2629 $formadmin = new FormAdmin($db);
2630 
2631 // Set dir where external modules are installed
2632 if (!dol_is_dir($dirins)) {
2633  dol_mkdir($dirins);
2634 }
2635 $dirins_ok = (dol_is_dir($dirins));
2636 
2637 $help_url = '';
2638 $morejs = array(
2639  '/includes/ace/src/ace.js',
2640  '/includes/ace/src/ext-statusbar.js',
2641  '/includes/ace/src/ext-language_tools.js',
2642  //'/includes/ace/src/ext-chromevox.js'
2643 );
2644 $morecss = array();
2645 
2646 llxHeader('', $langs->trans("ModuleBuilder"), $help_url, '', 0, 0, $morejs, $morecss, '', 'classforhorizontalscrolloftabs');
2647 
2648 
2649 $text = $langs->trans("ModuleBuilder");
2650 
2651 print load_fiche_titre($text, '', 'title_setup');
2652 
2653 print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModuleBuilderDesc", 'https://wiki.dolibarr.org/index.php/Module_development#Create_your_module').'</span>';
2654 print '<br class="hideonsmartphone">';
2655 
2656 //print $textforlistofdirs;
2657 //print '<br>';
2658 //var_dump($listofmodules);
2659 
2660 
2661 $message = '';
2662 if (!$dirins) {
2663  $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
2664  $allowfromweb = -1;
2665 } else {
2666  if ($dirins_ok) {
2667  if (!is_writable(dol_osencode($dirins))) {
2668  $langs->load("errors");
2669  $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins));
2670  $allowfromweb = 0;
2671  }
2672  } else {
2673  $message = info_admin($langs->trans("NotExistsDirect", $dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
2674  $allowfromweb = 0;
2675  }
2676 }
2677 if ($message) {
2678  print $message;
2679 }
2680 
2681 //print $langs->trans("ModuleBuilderDesc3", count($listofmodules), $FILEFLAG).'<br>';
2682 $infomodulesfound = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', $langs->trans("ModuleBuilderDesc3", count($listofmodules)).'<br><br>'.$langs->trans("ModuleBuilderDesc4", $FILEFLAG).'<br>'.$textforlistofdirs).'</div>';
2683 
2684 
2685 
2686 $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
2687 $allowonlineinstall = true;
2688 if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
2689  $allowonlineinstall = false;
2690 }
2691 if (empty($allowonlineinstall)) {
2692  if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
2693  // Show clean message
2694  $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'));
2695  } else {
2696  // Show technical message
2697  $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'), 0, 0, 1, 'warning');
2698  }
2699 
2700  print $message;
2701 
2702  llxFooter();
2703  exit(0);
2704 }
2705 
2706 
2707 // Load module descriptor
2708 $error = 0;
2709 $moduleobj = null;
2710 
2711 
2712 if (!empty($module) && $module != 'initmodule' && $module != 'deletemodule') {
2713  $modulelowercase = strtolower($module);
2714  $loadclasserrormessage = '';
2715 
2716  // Load module
2717  try {
2718  $fullpathdirtodescriptor = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2719 
2720  //throw(new Exception());
2721  dol_include_once($fullpathdirtodescriptor);
2722 
2723  $class = 'mod'.$module;
2724  } catch (Throwable $e) { // This is called in PHP 7 only (includes Error and Exception)
2725  $loadclasserrormessage = $e->getMessage()."<br>\n";
2726  $loadclasserrormessage .= 'File: '.$e->getFile()."<br>\n";
2727  $loadclasserrormessage .= 'Line: '.$e->getLine()."<br>\n";
2728  }
2729 
2730  if (class_exists($class)) {
2731  try {
2732  $moduleobj = new $class($db);
2733  } catch (Exception $e) {
2734  $error++;
2735  print $e->getMessage();
2736  }
2737  } else {
2738  if (empty($forceddirread)) {
2739  $error++;
2740  }
2741  $langs->load("errors");
2742  print '<!-- ErrorFailedToLoadModuleDescriptorForXXX -->';
2743  print img_warning('').' '.$langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
2744  print $loadclasserrormessage;
2745  }
2746 }
2747 
2748 print '<br>';
2749 
2750 
2751 // Tabs for all modules
2752 $head = array();
2753 $h = 0;
2754 
2755 $head[$h][0] = $_SERVER["PHP_SELF"].'?module=initmodule';
2756 $head[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewModule").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
2757 $head[$h][2] = 'initmodule';
2758 $h++;
2759 
2760 $linktoenabledisable = '';
2761 
2762 if (is_array($listofmodules) && count($listofmodules) > 0) {
2763  // Define $linktoenabledisable
2764  $modulelowercase = strtolower($module);
2765  $const_name = 'MAIN_MODULE_'.strtoupper($module);
2766 
2767  $param = '';
2768  if ($tab) {
2769  $param .= '&tab='.urlencode($tab);
2770  }
2771  if ($module) {
2772  $param .= '&module='.urlencode($module);
2773  }
2774  if ($tabobj) {
2775  $param .= '&tabobj='.urlencode($tabobj);
2776  }
2777 
2778  $urltomodulesetup = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?search_keyword='.urlencode($module).'">'.$langs->trans('Home').'-'.$langs->trans("Setup").'-'.$langs->trans("Modules").'</a>';
2779 
2780  // Define $linktoenabledisable to show after module title
2781  if (isModEnabled($modulelowercase)) { // If module is already activated
2782  $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=reset&token='.newToken().'&value=mod'.$module.$param.'">';
2783  $linktoenabledisable .= img_picto($langs->trans("Activated"), 'switch_on', '', false, 0, 0, '', '', 1);
2784  $linktoenabledisable .= '</a>';
2785 
2786  $linktoenabledisable .= $form->textwithpicto('', $langs->trans("Warning").' : '.$langs->trans("ModuleIsLive"), -1, 'warning');
2787 
2788  $objMod = $moduleobj;
2789  $backtourlparam = '';
2790  $backtourlparam .= ($backtourlparam ? '&' : '?').'module='.$module; // No urlencode here, done later
2791  if ($tab) {
2792  $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later
2793  }
2794  $backtourl = $_SERVER["PHP_SELF"].$backtourlparam;
2795 
2796  $regs = array();
2797  if (is_array($objMod->config_page_url)) {
2798  $i = 0;
2799  foreach ($objMod->config_page_url as $page) {
2800  $urlpage = $page;
2801  if ($i++) {
2802  $linktoenabledisable .= ' <a href="'.$urlpage.'" title="'.$langs->trans($page).'">'.img_picto(ucfirst($page), "setup").'</a>';
2803  // print '<a href="'.$page.'">'.ucfirst($page).'</a>&nbsp;';
2804  } else {
2805  if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) {
2806  $urltouse = dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1);
2807  $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>';
2808  } else {
2809  // Case standard admin page (not a page provided by the
2810  // module but a page provided by dolibarr)
2811  $urltouse = DOL_URL_ROOT.'/admin/'.$urlpage;
2812  $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>';
2813  }
2814  }
2815  }
2816  } elseif (preg_match('/^([^@]+)@([^@]+)$/i', $objMod->config_page_url, $regs)) {
2817  $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>';
2818  }
2819  } else {
2820  if (!empty($moduleobj)) {
2821  $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=set&token='.newToken().'&value=mod'.$module.$param.'">';
2822  $linktoenabledisable .= img_picto($langs->trans("ModuleIsNotActive", $urltomodulesetup), 'switch_off', 'style="padding-right: 8px"', false, 0, 0, '', 'classfortooltip', 1);
2823  $linktoenabledisable .= "</a>\n";
2824  }
2825  }
2826 
2827  // Loop to show tab of each module
2828  foreach ($listofmodules as $tmpmodule => $tmpmodulearray) {
2829  $head[$h][0] = $_SERVER["PHP_SELF"].'?module='.$tmpmodulearray['modulenamewithcase'].($forceddirread ? '@'.$dirread : '');
2830  $head[$h][1] = $tmpmodulearray['modulenamewithcase'];
2831  $head[$h][2] = $tmpmodulearray['modulenamewithcase'];
2832 
2833  if ($tmpmodulearray['modulenamewithcase'] == $module) {
2834  $head[$h][4] = '<span class="inline-block">'.$linktoenabledisable.'</span>';
2835  }
2836 
2837  $h++;
2838  }
2839 }
2840 
2841 $head[$h][0] = $_SERVER["PHP_SELF"].'?module=deletemodule';
2842 $head[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
2843 $head[$h][2] = 'deletemodule';
2844 $h++;
2845 
2846 
2847 print dol_get_fiche_head($head, $module, '', -1, '', 0, $infomodulesfound, '', 8); // Modules
2848 
2849 if ($module == 'initmodule') {
2850  // New module
2851  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2852  print '<input type="hidden" name="token" value="'.newToken().'">';
2853  print '<input type="hidden" name="action" value="initmodule">';
2854  print '<input type="hidden" name="module" value="initmodule">';
2855 
2856  //print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc2", 'conf/conf.php', $newdircustom).'</span><br>';
2857  print '<br>';
2858 
2859  print '<div class="tagtable">';
2860 
2861  print '<div class="tagtr"><div class="tagtd">';
2862  print '<span class="opacitymedium">'.$langs->trans("IdModule").'</span>';
2863  print '</div><div class="tagtd">';
2864  print '<input type="text" name="idmodule" class="width75" value="500000" placeholder="'.dol_escape_htmltag($langs->trans("IdModule")).'">';
2865  print '<span class="opacitymedium">';
2866  print ' &nbsp; (';
2867  print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
2868  print ' - ';
2869  print '<a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>';
2870  print ')';
2871  print '</span>';
2872  print '</div></div>';
2873 
2874  print '<div class="tagtr"><div class="tagtd">';
2875  print '<span class="opacitymedium">'.$langs->trans("ModuleName").'</span>';
2876  print '</div><div class="tagtd">';
2877  print '<input type="text" name="modulename" value="'.dol_escape_htmltag($modulename).'" autofocus>';
2878  print ' '.$form->textwithpicto('', $langs->trans("EnterNameOfModuleDesc"));
2879  print '</div></div>';
2880 
2881  print '<div class="tagtr"><div class="tagtd">';
2882  print '<span class="opacitymedium">'.$langs->trans("Description").'</span>';
2883  print '</div><div class="tagtd">';
2884  print '<input type="text" name="description" value="" class="minwidth500"><br>';
2885  print '</div></div>';
2886 
2887  print '<div class="tagtr"><div class="tagtd">';
2888  print '<span class="opacitymedium">'.$langs->trans("Version").'</span>';
2889  print '</div><div class="tagtd">';
2890  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")).'">';
2891  print '</div></div>';
2892 
2893  print '<div class="tagtr"><div class="tagtd">';
2894  print '<span class="opacitymedium">'.$langs->trans("Family").'</span>';
2895  print '</div><div class="tagtd">';
2896  print '<select name="family" id="family" class="minwidth400">';
2897  $arrayoffamilies = array(
2898  'hr' => "ModuleFamilyHr",
2899  'crm' => "ModuleFamilyCrm",
2900  'srm' => "ModuleFamilySrm",
2901  'financial' => 'ModuleFamilyFinancial',
2902  'products' => 'ModuleFamilyProducts',
2903  'projects' => 'ModuleFamilyProjects',
2904  'ecm' => 'ModuleFamilyECM',
2905  'technic' => 'ModuleFamilyTechnic',
2906  'portal' => 'ModuleFamilyPortal',
2907  'interface' => 'ModuleFamilyInterface',
2908  'base' => 'ModuleFamilyBase',
2909  'other' => 'ModuleFamilyOther'
2910  );
2911  foreach ($arrayoffamilies as $key => $value) {
2912  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>';
2913  }
2914  print '</select>';
2915  print ajax_combobox("family");
2916  print '</div></div>';
2917 
2918  print '<div class="tagtr"><div class="tagtd">';
2919  print '<span class="opacitymedium">'.$langs->trans("Picto").'</span>';
2920  print '</div><div class="tagtd">';
2921  print '<input type="text" name="idpicto" value="'.(GETPOSTISSET('idpicto') ? GETPOST('idpicto') : getDolGlobalString('MODULEBUILDER_DEFAULTPICTO', 'fa-file-o')).'" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
2922  print $form->textwithpicto('', $langs->trans("Example").': fa-file-o, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
2923  print '</div></div>';
2924 
2925  print '<div class="tagtr"><div class="tagtd">';
2926  print '<span class="opacitymedium">'.$langs->trans("EditorName").'</span>';
2927  print '</div><div class="tagtd">';
2928  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>';
2929  print '</div></div>';
2930 
2931  print '<div class="tagtr"><div class="tagtd">';
2932  print '<span class="opacitymedium">'.$langs->trans("EditorUrl").'</span>';
2933  print '</div><div class="tagtd">';
2934  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>';
2935  print '</div></div>';
2936 
2937  print '<br><input type="submit" class="button" name="create" value="'.dol_escape_htmltag($langs->trans("Create")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
2938  print '</form>';
2939 } elseif ($module == 'deletemodule') {
2940  print '<!-- Form to init a module -->'."\n";
2941  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="delete">';
2942  print '<input type="hidden" name="token" value="'.newToken().'">';
2943  print '<input type="hidden" name="action" value="confirm_deletemodule">';
2944  print '<input type="hidden" name="module" value="deletemodule">';
2945 
2946  print $langs->trans("EnterNameOfModuleToDeleteDesc").'<br><br>';
2947 
2948  print '<input type="text" name="module" placeholder="'.dol_escape_htmltag($langs->trans("ModuleKey")).'" value="">';
2949  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Delete").'"'.($dirins ? '' : ' disabled="disabled"').'>';
2950  print '</form>';
2951 } elseif (!empty($module)) {
2952  // Tabs for module
2953  if (!$error) {
2954  $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2955 
2956  $head2 = array();
2957  $h = 0;
2958 
2959  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=description&module='.$module.($forceddirread ? '@'.$dirread : '');
2960  $head2[$h][1] = $langs->trans("Description");
2961  $head2[$h][2] = 'description';
2962  $h++;
2963 
2964  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '');
2965  $head2[$h][1] = $langs->trans("Objects");
2966  $head2[$h][2] = 'objects';
2967  $h++;
2968 
2969  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=languages&module='.$module.($forceddirread ? '@'.$dirread : '');
2970  $head2[$h][1] = $langs->trans("Languages");
2971  $head2[$h][2] = 'languages';
2972  $h++;
2973 
2974  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '');
2975  $head2[$h][1] = $langs->trans("Dictionaries");
2976  $head2[$h][2] = 'dictionaries';
2977  $h++;
2978 
2979  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=permissions&module='.$module.($forceddirread ? '@'.$dirread : '');
2980  $head2[$h][1] = $langs->trans("Permissions");
2981  $head2[$h][2] = 'permissions';
2982  $h++;
2983 
2984  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=tabs&module='.$module.($forceddirread ? '@'.$dirread : '');
2985  $head2[$h][1] = $langs->trans("Tabs");
2986  $head2[$h][2] = 'tabs';
2987  $h++;
2988 
2989  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=menus&module='.$module.($forceddirread ? '@'.$dirread : '');
2990  $head2[$h][1] = $langs->trans("Menus");
2991  $head2[$h][2] = 'menus';
2992  $h++;
2993 
2994  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=hooks&module='.$module.($forceddirread ? '@'.$dirread : '');
2995  $head2[$h][1] = $langs->trans("Hooks");
2996  $head2[$h][2] = 'hooks';
2997  $h++;
2998 
2999  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=triggers&module='.$module.($forceddirread ? '@'.$dirread : '');
3000  $head2[$h][1] = $langs->trans("Triggers");
3001  $head2[$h][2] = 'triggers';
3002  $h++;
3003 
3004  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=widgets&module='.$module.($forceddirread ? '@'.$dirread : '');
3005  $head2[$h][1] = $langs->trans("Widgets");
3006  $head2[$h][2] = 'widgets';
3007  $h++;
3008 
3009  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=exportimport&module='.$module.($forceddirread ? '@'.$dirread : '');
3010  $head2[$h][1] = $langs->trans("Export").'-'.$langs->trans("Import");
3011  $head2[$h][2] = 'exportimport';
3012  $h++;
3013 
3014  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=css&module='.$module.($forceddirread ? '@'.$dirread : '');
3015  $head2[$h][1] = $langs->trans("CSS");
3016  $head2[$h][2] = 'css';
3017  $h++;
3018 
3019  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=js&module='.$module.($forceddirread ? '@'.$dirread : '');
3020  $head2[$h][1] = $langs->trans("JS");
3021  $head2[$h][2] = 'js';
3022  $h++;
3023 
3024  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cli&module='.$module.($forceddirread ? '@'.$dirread : '');
3025  $head2[$h][1] = $langs->trans("CLI");
3026  $head2[$h][2] = 'cli';
3027  $h++;
3028 
3029  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cron&module='.$module.($forceddirread ? '@'.$dirread : '');
3030  $head2[$h][1] = $langs->trans("CronList");
3031  $head2[$h][2] = 'cron';
3032  $h++;
3033 
3034  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=specifications&module='.$module.($forceddirread ? '@'.$dirread : '');
3035  $head2[$h][1] = $langs->trans("Documentation");
3036  $head2[$h][2] = 'specifications';
3037  $h++;
3038 
3039  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=buildpackage&module='.$module.($forceddirread ? '@'.$dirread : '');
3040  $head2[$h][1] = $langs->trans("BuildPackage");
3041  $head2[$h][2] = 'buildpackage';
3042  $h++;
3043 
3044  $MAXTABFOROBJECT = 15;
3045 
3046  print '<!-- Section for a given module -->';
3047 
3048  // Note module is inside $dirread
3049 
3050  if ($tab == 'description') {
3051  print '<!-- tab=description -->'."\n";
3052  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3053  $pathtofilereadme = $modulelowercase.'/README.md';
3054  $pathtochangelog = $modulelowercase.'/ChangeLog.md';
3055 
3056  if ($action != 'editfile' || empty($file)) {
3057  $morehtmlright = '';
3058  if (realpath($dirread.'/'.$modulelowercase) != $dirread.'/'.$modulelowercase) {
3059  $morehtmlright = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', '<span class="opacitymedium">'.$langs->trans("RealPathOfModule").' :</span> <strong class="wordbreak">'.realpath($dirread.'/'.$modulelowercase).'</strong>').'</div>';
3060  }
3061 
3062  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, $morehtmlright, '', $MAXTABFOROBJECT, 'formodulesuffix'); // Description - level 2
3063 
3064  print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc".$tab).'</span>';
3065  print '<br><br>';
3066 
3067  print '<table>';
3068 
3069  print '<tr><td>';
3070  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3071  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>';
3072  print '</td></tr>';
3073 
3074  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ReadmeFile").' : <strong class="wordbreak">'.$pathtofilereadme.'</strong>';
3075  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>';
3076  print '</td></tr>';
3077 
3078  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ChangeLog").' : <strong class="wordbreak">'.$pathtochangelog.'</strong>';
3079  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>';
3080  print '</td></tr>';
3081 
3082  print '</table>';
3083  print '<br>';
3084 
3085  print load_fiche_titre($form->textwithpicto($langs->trans("DescriptorFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofile), '', '');
3086 
3087  if (!empty($moduleobj)) {
3088  print '<div class="underbanner clearboth"></div>';
3089  print '<div class="fichecenter">';
3090 
3091  print '<table class="border centpercent">';
3092  print '<tr class="liste_titre"><td class="titlefield">';
3093  print $langs->trans("Parameter");
3094  print '</td><td>';
3095  print $langs->trans("Value");
3096  print '</td></tr>';
3097 
3098  print '<tr><td>';
3099  print $langs->trans("IdModule");
3100  print '</td><td>';
3101  print $moduleobj->numero;
3102  print '<span class="opacitymedium">';
3103  print ' &nbsp; (';
3104  print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
3105  print ' - <a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>)';
3106  print '</span>';
3107  print '</td></tr>';
3108 
3109  print '<tr><td>';
3110  print $langs->trans("ModuleName");
3111  print '</td><td>';
3112  print $moduleobj->getName();
3113  print '</td></tr>';
3114 
3115  print '<tr><td>';
3116  print $langs->trans("Description");
3117  print '</td><td>';
3118  print $moduleobj->getDesc();
3119  print '</td></tr>';
3120 
3121  print '<tr><td>';
3122  print $langs->trans("Version");
3123  print '</td><td>';
3124  print $moduleobj->getVersion();
3125  print '</td></tr>';
3126 
3127  print '<tr><td>';
3128  print $langs->trans("Family");
3129  //print "<br>'crm','financial','hr','projects','products','ecm','technic','interface','other'";
3130  print '</td><td>';
3131  print $moduleobj->family;
3132  print '</td></tr>';
3133 
3134  print '<tr><td>';
3135  print $langs->trans("Picto");
3136  print '</td><td>';
3137  print $moduleobj->picto;
3138  print ' &nbsp; '.img_picto('', $moduleobj->picto, 'class="valignmiddle pictomodule paddingrightonly"');
3139  print '</td></tr>';
3140 
3141  print '<tr><td>';
3142  print $langs->trans("EditorName");
3143  print '</td><td>';
3144  print $moduleobj->editor_name;
3145  print '</td></tr>';
3146 
3147  print '<tr><td>';
3148  print $langs->trans("EditorUrl");
3149  print '</td><td>';
3150  if (!empty($moduleobj->editor_url)) {
3151  print '<a href="'.$moduleobj->editor_url.'" target="_blank" rel="noopener">'.$moduleobj->editor_url.' '.img_picto('', 'globe').'</a>';
3152  }
3153  print '</td></tr>';
3154 
3155  print '</table>';
3156  } else {
3157  print $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
3158  }
3159 
3160  if (!empty($moduleobj)) {
3161  print '<br><br>';
3162 
3163  // Readme file
3164  print load_fiche_titre($form->textwithpicto($langs->trans("ReadmeFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofilereadme), '', '');
3165 
3166  print '<!-- readme file -->';
3167  if (dol_is_file($dirread.'/'.$pathtofilereadme)) {
3168  print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getDescLong().'</div>';
3169  } else {
3170  print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtofilereadme).'</span>';
3171  }
3172 
3173  print '<br><br>';
3174 
3175  // ChangeLog
3176  print load_fiche_titre($form->textwithpicto($langs->trans("ChangeLog"), $langs->transnoentitiesnoconv("File").' '.$pathtochangelog), '', '');
3177 
3178  print '<!-- changelog file -->';
3179  if (dol_is_file($dirread.'/'.$pathtochangelog)) {
3180  print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getChangeLog().'</div>';
3181  } else {
3182  print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtochangelog).'</span>';
3183  }
3184  }
3185 
3186  print dol_get_fiche_end();
3187  } else { // Edit text file
3188  $fullpathoffile = dol_buildpath($file, 0, 1); // Description - level 2
3189 
3190  if ($fullpathoffile) {
3191  $content = file_get_contents($fullpathoffile);
3192  }
3193 
3194  // New module
3195  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3196  print '<input type="hidden" name="token" value="'.newToken().'">';
3197  print '<input type="hidden" name="action" value="savefile">';
3198  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3199  print '<input type="hidden" name="tab" value="'.$tab.'">';
3200  print '<input type="hidden" name="module" value="'.$module.'">';
3201 
3202  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', 0, 'formodulesuffix');
3203 
3204  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%', '');
3205  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3206 
3207  print dol_get_fiche_end();
3208 
3209  print '<center>';
3210  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3211  print ' &nbsp; ';
3212  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3213  print '</center>';
3214 
3215  print '</form>';
3216  }
3217  } else {
3218  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', $MAXTABFOROBJECT, 'formodulesuffix'); // Level 2
3219  }
3220 
3221  if ($tab == 'languages') {
3222  print '<!-- tab=languages -->'."\n";
3223  if ($action != 'editfile' || empty($file)) {
3224  print '<span class="opacitymedium">'.$langs->trans("LanguageDefDesc").'</span><br>';
3225  print '<br>';
3226 
3227 
3228  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3229  print '<input type="hidden" name="token" value="'.newToken().'">';
3230  print '<input type="hidden" name="action" value="addlanguage">';
3231  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3232  print '<input type="hidden" name="tab" value="'.$tab.'">';
3233  print '<input type="hidden" name="module" value="'.$module.'">';
3234  print $formadmin->select_language($conf->global->MAIN_LANG_DEFAULT, 'newlangcode', 0, 0, 1, 0, 0, 'minwidth300', 1);
3235  print '<input type="submit" name="addlanguage" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("AddLanguageFile")).'"><br>';
3236  print '</form>';
3237 
3238  print '<br>';
3239  print '<br>';
3240 
3241  $modulelowercase = strtolower($module);
3242 
3243  // Dir for module
3244  $diroflang = dol_buildpath($modulelowercase, 0);
3245  $diroflang .= '/langs';
3246  $langfiles = dol_dir_list($diroflang, 'files', 1, '\.lang$');
3247 
3248  if (!preg_match('/custom/', $dirread)) {
3249  // If this is not a module into custom
3250  $diroflang = $dirread;
3251  $diroflang .= '/langs';
3252  $langfiles = dol_dir_list($diroflang, 'files', 1, $modulelowercase.'\.lang$');
3253  }
3254 
3255  print '<table class="none">';
3256  foreach ($langfiles as $langfile) {
3257  $pathtofile = $modulelowercase.'/langs/'.$langfile['relativename'];
3258  if (!preg_match('/custom/', $dirread)) { // If this is not a module into custom
3259  $pathtofile = 'langs/'.$langfile['relativename'];
3260  }
3261  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("LanguageFile").' '.basename(dirname($pathtofile)).' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3262  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>';
3263  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>';
3264  print '</td>';
3265  }
3266  print '</table>';
3267  } else {
3268  // Edit text language file
3269 
3270  //print $langs->trans("UseAsciiDocFormat").'<br>';
3271 
3272  $fullpathoffile = dol_buildpath($file, 0);
3273 
3274  $content = file_get_contents($fullpathoffile);
3275 
3276  // New module
3277  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3278  print '<input type="hidden" name="token" value="'.newToken().'">';
3279  print '<input type="hidden" name="action" value="savefile">';
3280  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3281  print '<input type="hidden" name="tab" value="'.$tab.'">';
3282  print '<input type="hidden" name="module" value="'.$module.'">';
3283 
3284  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3285  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'text'));
3286  print '<br>';
3287  print '<center>';
3288  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3289  print ' &nbsp; ';
3290  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3291  print '</center>';
3292 
3293  print '</form>';
3294  }
3295  }
3296 
3297  if ($tab == 'objects') {
3298  print '<!-- tab=objects -->'."\n";
3299  $head3 = array();
3300  $h = 0;
3301 
3302  // Dir for module
3303  $dir = $dirread.'/'.$modulelowercase.'/class';
3304 
3305  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=newobject';
3306  $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewObjectInModulebuilder").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
3307  $head3[$h][2] = 'newobject';
3308  $h++;
3309 
3310  // Scan for object class files
3311  $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
3312 
3313  $firstobjectname = '';
3314  foreach ($listofobject as $fileobj) {
3315  if (preg_match('/^api_/', $fileobj['name'])) {
3316  continue;
3317  }
3318  if (preg_match('/^actions_/', $fileobj['name'])) {
3319  continue;
3320  }
3321 
3322  $tmpcontent = file_get_contents($fileobj['fullname']);
3323  if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
3324  //$objectname = preg_replace('/\.txt$/', '', $fileobj['name']);
3325  $objectname = $reg[1];
3326  if (empty($firstobjectname)) {
3327  $firstobjectname = $objectname;
3328  }
3329  $pictoname = 'generic';
3330  if (preg_match('/\$picto\s*=\s*["\']([^"\']+)["\']/', $tmpcontent, $reg)) {
3331  $pictoname = $reg[1];
3332  }
3333 
3334  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname;
3335  $head3[$h][1] = img_picto('', $pictoname, 'class="pictofixedwidth valignmiddle"').$objectname;
3336  $head3[$h][2] = $objectname;
3337  $h++;
3338  }
3339  }
3340 
3341  if ($h > 1) {
3342  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=deleteobject';
3343  $head3[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
3344  $head3[$h][2] = 'deleteobject';
3345  $h++;
3346  }
3347 
3348  // 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.
3349  if ($tabobj == 'newobjectifnoobj') {
3350  if ($firstobjectname) {
3351  $tabobj = $firstobjectname;
3352  } else {
3353  $tabobj = 'newobject';
3354  }
3355  }
3356 
3357  print dol_get_fiche_head($head3, $tabobj, '', -1, '', 0, '', '', 0, 'forobjectsuffix'); // Level 3
3358 
3359  if ($tabobj == 'newobject') {
3360  // New object tab
3361  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3362  print '<input type="hidden" name="token" value="'.newToken().'">';
3363  print '<input type="hidden" name="action" value="initobject">';
3364  print '<input type="hidden" name="tab" value="objects">';
3365  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3366 
3367  print '<span class="opacitymedium">'.$langs->trans("EnterNameOfObjectDesc").'</span><br><br>';
3368 
3369  print '<div class="tagtable">';
3370 
3371  print '<div class="tagtr"><div class="tagtd">';
3372  print '<span class="opacitymedium">'.$langs->trans("ObjectKey").'</span> &nbsp; ';
3373  print '</div><div class="tagtd">';
3374  print '<input type="text" name="objectname" maxlength="64" value="'.dol_escape_htmltag(GETPOST('objectname', 'alpha') ? GETPOST('objectname', 'alpha') : $modulename).'" autofocus><br>';
3375  print '</div></div>';
3376 
3377  print '<div class="tagtr"><div class="tagtd">';
3378  print '<span class="opacitymedium">'.$langs->trans("Picto").'</span> &nbsp; ';
3379  print '</div><div class="tagtd">';
3380  print '<input type="text" name="idpicto" value="fa-file-o" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
3381  print $form->textwithpicto('', $langs->trans("Example").': fa-file-o, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
3382  print '</div></div>';
3383 
3384  print '<div class="tagtr"><div class="tagtd">';
3385  print '<span class="opacitymedium">'.$langs->trans("DefinePropertiesFromExistingTable").'</span> &nbsp; ';
3386  print '</div><div class="tagtd">';
3387  print '<input type="text" name="initfromtablename" value="'.GETPOST('initfromtablename').'" placeholder="'.$langs->trans("TableName").'">';
3388  print $form->textwithpicto('', $langs->trans("DefinePropertiesFromExistingTableDesc").'<br>'.$langs->trans("DefinePropertiesFromExistingTableDesc2"));
3389  print '</div></div>';
3390 
3391  print '</div>';
3392 
3393  print '<br>';
3394  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>';
3395  print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
3396  print '<input type="checkbox" name="generatepermissions" id="generatepermissions" value="generatepermissions"> <label for="generatepermissions">'.$form->textwithpicto($langs->trans("GeneratePermissions"), $langs->trans("GeneratePermissionsHelp")).'</label><br>';
3397  print '<br>';
3398  print '<input type="submit" class="button small" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3399  print '<br>';
3400  print '<br>';
3401  /*
3402  print '<br>';
3403  print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
3404  print '<br>';
3405  print '<br>';
3406  //print '<input type="checkbox" name="initfromtablecheck"> ';
3407  print $langs->trans("InitStructureFromExistingTable");
3408  print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
3409  print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3410  print '<br>';
3411  */
3412 
3413  print '</form>';
3414  } elseif ($tabobj == 'deleteobject') {
3415  // Delete object tab
3416  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3417  print '<input type="hidden" name="token" value="'.newToken().'">';
3418  print '<input type="hidden" name="action" value="confirm_deleteobject">';
3419  print '<input type="hidden" name="tab" value="objects">';
3420  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3421 
3422  print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
3423 
3424  print '<input type="text" name="objectname" value="'.dol_escape_htmltag($modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'">';
3425  print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3426  print '</form>';
3427  } else {
3428  // tabobj = module
3429  if ($action == 'deleteproperty') {
3430  $formconfirm = $form->formconfirm(
3431  $_SERVER["PHP_SELF"].'?propertykey='.urlencode(GETPOST('propertykey', 'alpha')).'&objectname='.urlencode($objectname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj),
3432  $langs->trans('Delete'),
3433  $langs->trans('ConfirmDeleteProperty', GETPOST('propertykey', 'alpha')),
3434  'confirm_deleteproperty',
3435  '',
3436  0,
3437  1
3438  );
3439 
3440  // Print form confirm
3441  print $formconfirm;
3442  }
3443 
3444  if ($action != 'editfile' || empty($file)) {
3445  try {
3446  //$pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3447 
3448  $pathtoclass = strtolower($module).'/class/'.strtolower($tabobj).'.class.php';
3449  $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'.class.php';
3450  $pathtoagenda = strtolower($module).'/'.strtolower($tabobj).'_agenda.php';
3451  $pathtocard = strtolower($module).'/'.strtolower($tabobj).'_card.php';
3452  $pathtodocument = strtolower($module).'/'.strtolower($tabobj).'_document.php';
3453  $pathtolist = strtolower($module).'/'.strtolower($tabobj).'_list.php';
3454  $pathtonote = strtolower($module).'/'.strtolower($tabobj).'_note.php';
3455  $pathtocontact = strtolower($module).'/'.strtolower($tabobj).'_contact.php';
3456  $pathtophpunit = strtolower($module).'/test/phpunit/'.strtolower($tabobj).'Test.php';
3457 
3458  // Try to load object class file
3459  clearstatcache(true);
3460  if (function_exists('opcache_invalidate')) {
3461  opcache_invalidate($dirread.'/'.$pathtoclass, true); // remove the include cache hell !
3462  }
3463 
3464  if (empty($forceddirread) && empty($dirread)) {
3465  $result = dol_include_once($pathtoclass);
3466  $stringofinclude = "dol_include_once(".$pathtoclass.")";
3467  } else {
3468  $result = @include_once $dirread.'/'.$pathtoclass;
3469  $stringofinclude = "@include_once ".$dirread.'/'.$pathtoclass;
3470  }
3471  if (class_exists($tabobj)) {
3472  try {
3473  $tmpobject = @new $tabobj($db);
3474  } catch (Exception $e) {
3475  dol_syslog('Failed to load Constructor of class: '.$e->getMessage(), LOG_WARNING);
3476  }
3477  } else {
3478  print '<span class="warning">'.$langs->trans('Failed to find the class '.$tabobj.' despite the '.$stringofinclude).'</span><br><br>';
3479  }
3480 
3481  // Define path for sql file
3482  $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
3483  $result = dol_buildpath($pathtosql);
3484  if (! dol_is_file($result)) {
3485  $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'.sql';
3486  $result = dol_buildpath($pathtosql);
3487  if (! dol_is_file($result)) {
3488  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
3489  $result = dol_buildpath($pathtosql);
3490  if (! dol_is_file($result)) {
3491  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
3492  $result = dol_buildpath($pathtosql);
3493  if (! dol_is_file($result)) {
3494  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'.sql';
3495  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields.sql';
3496  $result = dol_buildpath($pathtosql);
3497  } else {
3498  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields-'.strtolower($module).'.sql';
3499  }
3500  } else {
3501  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
3502  }
3503  } else {
3504  $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields.sql';
3505  }
3506  } else {
3507  $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
3508  }
3509  $pathtosqlroot = preg_replace('/\/llx_.*$/', '', $pathtosql);
3510 
3511  $pathtosqlkey = preg_replace('/\.sql$/', '.key.sql', $pathtosql);
3512  $pathtosqlextrakey = preg_replace('/\.sql$/', '.key.sql', $pathtosqlextra);
3513 
3514  $pathtolib = strtolower($module).'/lib/'.strtolower($module).'.lib.php';
3515  $pathtoobjlib = strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($tabobj).'.lib.php';
3516 
3517  if (is_object($tmpobject) && property_exists($tmpobject, 'picto')) {
3518  $pathtopicto = $tmpobject->picto;
3519  $realpathtopicto = '';
3520  } else {
3521  $pathtopicto = strtolower($module).'/img/object_'.strtolower($tabobj).'.png';
3522  $realpathtopicto = $dirread.'/'.$pathtopicto;
3523  }
3524 
3525  //var_dump($pathtoclass);
3526  //var_dump($dirread);
3527  $realpathtoclass = $dirread.'/'.$pathtoclass;
3528  $realpathtoapi = $dirread.'/'.$pathtoapi;
3529  $realpathtoagenda = $dirread.'/'.$pathtoagenda;
3530  $realpathtocard = $dirread.'/'.$pathtocard;
3531  $realpathtodocument = $dirread.'/'.$pathtodocument;
3532  $realpathtolist = $dirread.'/'.$pathtolist;
3533  $realpathtonote = $dirread.'/'.$pathtonote;
3534  $realpathtocontact = $dirread.'/'.$pathtocontact;
3535  $realpathtophpunit = $dirread.'/'.$pathtophpunit;
3536  $realpathtosql = $dirread.'/'.$pathtosql;
3537  $realpathtosqlextra = $dirread.'/'.$pathtosqlextra;
3538  $realpathtosqlkey = $dirread.'/'.$pathtosqlkey;
3539  $realpathtosqlextrakey = $dirread.'/'.$pathtosqlextrakey;
3540  $realpathtolib = $dirread.'/'.$pathtolib;
3541  $realpathtoobjlib = $dirread.'/'.$pathtoobjlib;
3542 
3543  if (empty($realpathtoapi)) { // For compatibility with some old modules
3544  $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'s.class.php';
3545  $realpathtoapi = $dirread.'/'.$pathtoapi;
3546  }
3547 
3548  $urloflist = dol_buildpath('/'.$pathtolist, 1);
3549  $urlofcard = dol_buildpath('/'.$pathtocard, 1);
3550 
3551  $objs = array();
3552 
3553  print '<!-- section for object -->';
3554  print '<div class="fichehalfleft smallxxx">';
3555  // Main DAO class file
3556  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>';
3557  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>';
3558  print '<br>';
3559  // Image
3560  if ($realpathtopicto && dol_is_file($realpathtopicto)) {
3561  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>';
3562  //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>';
3563  print '<br>';
3564  } elseif (!empty($tmpobject)) {
3565  print '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : '.img_picto('', $tmpobject->picto, 'class="pictofixedwidth valignmiddle"').$tmpobject->picto;
3566  print '<br>';
3567  }
3568 
3569  // API file
3570  print '<br>';
3571  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>';
3572  if (dol_is_file($realpathtoapi)) {
3573  $file = file_get_contents($realpathtoapi);
3574  if (preg_match('/var '.$tabobj.'\s+([^\s]*)\s/ims', $file, $objs)) {
3575  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>';
3576  print ' ';
3577  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>';
3578  print ' &nbsp; ';
3579  if (empty($conf->global->$const_name)) { // If module is not activated
3580  print '<a href="#" class="classfortooltip" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled", $module).'"><strike>'.$langs->trans("ApiExplorer").'</strike></a>';
3581  } else {
3582  print '<a href="'.DOL_URL_ROOT.'/api/index.php/explorer/" target="apiexplorer">'.$langs->trans("ApiExplorer").'</a>';
3583  }
3584  } else {
3585  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>';
3586  }
3587  } else {
3588  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>';
3589  }
3590  // PHPUnit
3591  print '<br>';
3592  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>';
3593  if (dol_is_file($realpathtophpunit)) {
3594  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>';
3595  print ' ';
3596  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>';
3597  } else {
3598  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>';
3599  }
3600  print '<br>';
3601 
3602  print '<br>';
3603 
3604  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>';
3605  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>';
3606  print '<br>';
3607  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>';
3608  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>';
3609  print '<br>';
3610 
3611  print '<br>';
3612  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>';
3613  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>';
3614  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>';
3615  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
3616  print '<br>';
3617  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>';
3618  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>';
3619  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
3620  print '<br>';
3621  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>';
3622  if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
3623  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>';
3624  print ' ';
3625  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>';
3626  print ' &nbsp; ';
3627  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>';
3628  } else {
3629  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>';
3630  }
3631  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
3632  print '<br>';
3633  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>';
3634  if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
3635  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>';
3636  print ' ';
3637  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>';
3638  } else {
3639  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>';
3640  }
3641  print '<br>';
3642  print '</div>';
3643 
3644  print '<div class="fichehalfleft smallxxxx">';
3645  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>';
3646  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>';
3647  print '<br>';
3648  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>';
3649  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>';
3650  print '<br>';
3651  // Page contact
3652  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>';
3653  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>';
3654  if (dol_is_file($realpathtocontact)) {
3655  print ' ';
3656  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>';
3657  } else {
3658  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>';
3659  }
3660  print '<br>';
3661  // Page document
3662  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>';
3663  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>';
3664  if (dol_is_file($realpathtodocument)) {
3665  print ' ';
3666  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>';
3667  } else {
3668  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>';
3669  }
3670  print '<br>';
3671  // Page notes
3672  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>';
3673  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>';
3674  if (dol_is_file($realpathtonote)) {
3675  print ' ';
3676  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>';
3677  } else {
3678  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>';
3679  }
3680  print '<br>';
3681  // Page agenda
3682  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>';
3683  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>';
3684  if (dol_is_file($realpathtoagenda)) {
3685  print ' ';
3686  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>';
3687  } else {
3688  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>';
3689  }
3690  print '<br>';
3691  print '<br>';
3692 
3693  print '</div>';
3694 
3695  print '<br><br><br>';
3696 
3697  if (!empty($tmpobject)) {
3698  $reflector = new ReflectionClass($tabobj);
3699  $reflectorproperties = $reflector->getProperties(); // Can also use get_object_vars
3700  $reflectorpropdefault = $reflector->getDefaultProperties(); // Can also use get_object_vars
3701  //$propstat = $reflector->getStaticProperties();
3702  //var_dump($reflectorpropdefault);
3703 
3704  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3705  print '<input type="hidden" name="token" value="'.newToken().'">';
3706  print '<input type="hidden" name="action" value="addproperty">';
3707  print '<input type="hidden" name="tab" value="objects">';
3708  print '<input type="hidden" name="page_y" value="">';
3709  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module.($forceddirread ? '@'.$dirread : '')).'">';
3710  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
3711 
3712  print '<input class="button smallpaddingimp" type="submit" name="regenerateclasssql" value="'.$langs->trans("RegenerateClassAndSql").'">';
3713  print '<br><br>';
3714 
3715  print load_fiche_titre($langs->trans("ObjectProperties"), '', '');
3716 
3717  print '<!-- Table with properties of object -->'."\n";
3718  print '<div class="div-table-responsive">';
3719  print '<table class="noborder small">';
3720  print '<tr class="liste_titre">';
3721  print '<th class="none">';
3722 
3723  $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>';
3724  print $form->textwithpicto($langs->trans("Code"), $htmltext, 1, 'help', 'extracss', 0, 3, 'propertyhelp');
3725 
3726  print '</th>';
3727  print '<th>';
3728  print $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey"));
3729  print '</th>';
3730  print '<th>'.$form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp').'</th>';
3731  print '<th>'.$form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")).'</th>';
3732  print '<th class="center">'.$form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")).'</th>';
3733  print '<th class="center">'.$langs->trans("DefaultValue").'</th>';
3734  print '<th class="center">'.$langs->trans("DatabaseIndex").'</th>';
3735  print '<th class="center">'.$form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp').'</th>';
3736  print '<th class="right">'.$langs->trans("Position").'</th>';
3737  print '<th class="center">'.$form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp').'</th>';
3738  print '<th class="center">'.$form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp').'</th>';
3739  print '<th class="center">'.$langs->trans("NotEditable").'</th>';
3740  print '<th class="center">'.$langs->trans("AlwaysEditable").'</th>';
3741  print '<th class="center">'.$form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")).'</th>';
3742  print '<th class="center">'.$form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")).'</th>';
3743  print '<th class="center">'.$langs->trans("CSSClass").'</th>';
3744  print '<th class="center">'.$langs->trans("CSSViewClass").'</th>';
3745  print '<th class="center">'.$langs->trans("CSSListClass").'</th>';
3746  print '<th>'.$langs->trans("KeyForTooltip").'</th>';
3747  print '<th class="center">'.$langs->trans("ShowOnCombobox").'</th>';
3748  //print '<th class="center">'.$langs->trans("Disabled").'</th>';
3749  print '<th>'.$form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")).'</th>';
3750  print '<th>'.$langs->trans("Comment").'</th>';
3751  print '<th class="none"></th>';
3752  print '</tr>';
3753 
3754  // We must use $reflectorpropdefault['fields'] to get list of fields because $tmpobject->fields may have been
3755  // modified during the constructor and we want value into head of class before constructor is called.
3756  //$properties = dol_sort_array($tmpobject->fields, 'position');
3757  $properties = dol_sort_array($reflectorpropdefault['fields'], 'position');
3758 
3759  if (!empty($properties)) {
3760  // Line to add a property
3761  print '<tr>';
3762  print '<td class="none"><input type="text" class="maxwidth75" name="propname" value="'.dol_escape_htmltag(GETPOST('propname', 'alpha')).'"></td>';
3763  print '<td><input type="text" class="maxwidth75" name="proplabel" value="'.dol_escape_htmltag(GETPOST('proplabel', 'alpha')).'"></td>';
3764  print '<td><input type="text" class="maxwidth75" name="proptype" value="'.dol_escape_htmltag(GETPOST('proptype', 'alpha')).'"></td>';
3765  print '<td><input type="text" class="maxwidth75" name="proparrayofkeyval" value="'.dol_escape_htmltag(GETPOST('proparrayofkeyval', 'restricthtml')).'"></td>';
3766  print '<td class="center"><input type="text" class="center maxwidth50" name="propnotnull" value="'.dol_escape_htmltag(GETPOST('propnotnull', 'alpha')).'"></td>';
3767  print '<td><input type="text" class="center maxwidth50" name="propdefault" value="'.dol_escape_htmltag(GETPOST('propdefault', 'alpha')).'"></td>';
3768  print '<td class="center"><input type="text" class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag(GETPOST('propindex', 'alpha')).'"></td>';
3769  print '<td class="center"><input type="text" class="maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag(GETPOST('propforeignkey', 'alpha')).'"></td>';
3770  print '<td class="right"><input type="text" class="right" size="2" name="propposition" value="'.dol_escape_htmltag(GETPOST('propposition', 'alpha')).'"></td>';
3771  print '<td class="center"><input type="text" class="center maxwidth50" name="propenabled" value="'.dol_escape_htmltag(GETPOST('propenabled', 'alpha')).'"></td>';
3772  print '<td class="center"><input type="text" class="center maxwidth50" name="propvisible" value="'.dol_escape_htmltag(GETPOST('propvisible', 'alpha')).'"></td>';
3773  print '<td class="center"><input type="text" class="center maxwidth50" name="propnoteditable" value="'.dol_escape_htmltag(GETPOST('propnoteditable', 'alpha')).'"></td>';
3774  print '<td class="center"><input type="text" class="center maxwidth50" name="propalwayseditable" value="'.dol_escape_htmltag(GETPOST('propalwayseditable', 'alpha')).'"></td>';
3775  print '<td class="center"><input type="text" class="center maxwidth50" name="propsearchall" value="'.dol_escape_htmltag(GETPOST('propsearchall', 'alpha')).'"></td>';
3776  print '<td class="center"><input type="text" class="center maxwidth50" name="propisameasure" value="'.dol_escape_htmltag(GETPOST('propisameasure', 'alpha')).'"></td>';
3777  print '<td class="center"><input type="text" class="maxwidth50" name="propcss" value="'.dol_escape_htmltag(GETPOST('propcss', 'alpha')).'"></td>';
3778  print '<td class="center"><input type="text" class="maxwidth50" name="propcssview" value="'.dol_escape_htmltag(GETPOST('propcssview', 'alpha')).'"></td>';
3779  print '<td class="center"><input type="text" class="maxwidth50" name="propcsslist" value="'.dol_escape_htmltag(GETPOST('propcsslist', 'alpha')).'"></td>';
3780  print '<td><input type="text" class="maxwidth50" name="prophelp" value="'.dol_escape_htmltag(GETPOST('prophelp', 'alpha')).'"></td>';
3781  print '<td class="center"><input type="text" class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag(GETPOST('propshowoncombobox', 'alpha')).'"></td>';
3782  //print '<td class="center"><input type="text" size="2" name="propdisabled" value="'.dol_escape_htmltag(GETPOST('propdisabled', 'alpha')).'"></td>';
3783  print '<td><input type="number" step="1" min="0" max="1" class="text maxwidth50" name="propvalidate" value="'.dol_escape_htmltag(GETPOST('propvalidate', 'alpha')).'"></td>';
3784  print '<td><input class="text maxwidth100" name="propcomment" value="'.dol_escape_htmltag(GETPOST('propcomment', 'alpha')).'"></td>';
3785  print '<td class="center tdstickyright tdstickyghostwhite">';
3786  print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
3787  print '</td></tr>';
3788 
3789  // List of existing properties
3790  foreach ($properties as $propkey => $propval) {
3791  /* If from Reflection
3792  if ($propval->class == $tabobj)
3793  {
3794  $propname=$propval->getName();
3795  $comment=$propval->getDocComment();
3796  $type=gettype($tmpobject->$propname);
3797  $default=$propdefault[$propname];
3798  // Discard generic properties
3799  if (in_array($propname, array('element', 'childtables', 'table_element', 'table_element_line', 'class_element_line', 'ismultientitymanaged'))) continue;
3800 
3801  // Keep or not lines
3802  if (in_array($propname, array('fk_element', 'lines'))) continue;
3803  }*/
3804 
3805  $propname = $propkey;
3806  $proplabel = $propval['label'];
3807  $proptype = $propval['type'];
3808  $proparrayofkeyval = !empty($propval['arrayofkeyval'])?$propval['arrayofkeyval']:'';
3809  $propnotnull = !empty($propval['notnull']) ? $propval['notnull'] : '0';
3810  $propdefault = !empty($propval['default'])?$propval['default']:'';
3811  $propindex = !empty($propval['index'])?$propval['index']:'';
3812  $propforeignkey = !empty($propval['foreignkey'])?$propval['foreignkey']:'';
3813  $propposition = $propval['position'];
3814  $propenabled = $propval['enabled'];
3815  $propvisible = $propval['visible'];
3816  $propnoteditable = !empty($propval['noteditable'])?$propval['noteditable']:0;
3817  $propalwayseditable = !empty($propval['alwayseditable'])?$propval['alwayseditable']:0;
3818  $propsearchall = !empty($propval['searchall'])?$propval['searchall']:0;
3819  $propisameasure = !empty($propval['isameasure'])?$propval['isameasure']:0;
3820  $propcss = !empty($propval['css'])?$propval['css']:'';
3821  $propcssview = !empty($propval['cssview'])?$propval['cssview']:'';
3822  $propcsslist = !empty($propval['csslist'])?$propval['csslist']:'';
3823  $prophelp = !empty($propval['help'])?$propval['help']:'';
3824  $propshowoncombobox = !empty($propval['showoncombobox'])?$propval['showoncombobox']:0;
3825  //$propdisabled=$propval['disabled'];
3826  $propvalidate = !empty($propval['validate'])?$propval['validate']:0;
3827  $propcomment = !empty($propval['comment'])?$propval['comment']:'';
3828 
3829  print '<tr class="oddeven">';
3830 
3831  print '<td class="tdsticky tdstickygray">';
3832  print dol_escape_htmltag($propname);
3833  print '</td>';
3834  print '<td>';
3835  print dol_escape_htmltag($proplabel);
3836  print '</td>';
3837  if ($action == 'editproperty' && $propname == $propertykey) {
3838  print '<td class="tdoverflowmax200">';
3839  print '<input type="hidden" name="propname" value="'.dol_escape_htmltag($propname).'">';
3840  print '<input type="hidden" name="proplabel" value="'.dol_escape_htmltag($proplabel).'">';
3841  print '<input name="proptype" value="'.dol_escape_htmltag($proptype).'"></input>';
3842  print '</td>';
3843  print '<td class="tdoverflowmax200">';
3844  print '<input name="proparrayofkeyval" value="';
3845  if (isset($proparrayofkeyval)) {
3846  if (is_array($proparrayofkeyval) || $proparrayofkeyval != '') {
3847  print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
3848  }
3849  }
3850  print '">';
3851  print '</input>';
3852  print '</td>';
3853  print '<td>';
3854  print '<input class="center width50" name="propnotnull" value="'.dol_escape_htmltag($propnotnull).'">';
3855  print '</td>';
3856  print '<td>';
3857  print '<input class="maxwidth50" name="propdefault" value="'.dol_escape_htmltag($propdefault).'">';
3858  print '</td>';
3859  print '<td class="center">';
3860  print '<input class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag($propindex).'">';
3861  print '</td>';
3862  print '<td>';
3863  print '<input class="center maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag($propforeignkey).'">';
3864  print '</td>';
3865  print '<td>';
3866  print '<input class="right width50" name="propposition" value="'.dol_escape_htmltag($propposition).'">';
3867  print '</td>';
3868  print '<td>';
3869  print '<input class="center" name="propenabled" size="2" value="'.dol_escape_htmltag($propenabled).'">';
3870  print '</td>';
3871  print '<td>';
3872  print '<input class="center" name="propvisible" size="2" value="'.dol_escape_htmltag($propvisible).'">';
3873  print '</td>';
3874  print '<td>';
3875  print '<input class="center" name="propnoteditable" size="2" value="'.dol_escape_htmltag($propnoteditable).'">';
3876  print '</td>';
3877  print '<td>';
3878  print '<input class="center" name="propalwayseditable" size="2" value="'.dol_escape_htmltag($propalwayseditable).'">';
3879  print '</td>';
3880  print '<td>';
3881  print '<input class="center" name="propsearchall" size="2" value="'.dol_escape_htmltag($propsearchall).'">';
3882  print '</td>';
3883  print '<td>';
3884  print '<input class="center" name="propisameasure" size="2" value="'.dol_escape_htmltag($propisameasure).'">';
3885  print '</td>';
3886  print '<td>';
3887  print '<input class="center maxwidth50" name="propcss" value="'.dol_escape_htmltag($propcss).'">';
3888  print '</td>';
3889  print '<td>';
3890  print '<input class="center maxwidth50" name="propcssview" value="'.dol_escape_htmltag($propcssview).'">';
3891  print '</td>';
3892  print '<td>';
3893  print '<input class="center maxwidth50" name="propcsslist" value="'.dol_escape_htmltag($propcsslist).'">';
3894  print '</td>';
3895  print '<td>';
3896  print '<input class="maxwidth100" name="prophelp" value="'.dol_escape_htmltag($prophelp).'">';
3897  print '</td>';
3898  print '<td>';
3899  print '<input class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag($propshowoncombobox).'">';
3900  print '</td>';
3901  print '<td>';
3902  print '<input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag($propvalidate).'">';
3903  print '</td>';
3904  print '<td>';
3905  print '<input class="maxwidth100" name="propcomment" value="'.dol_escape_htmltag($propcomment).'">';
3906  print '</td>';
3907  print '<td class="center tdstickyright tdstickyghostwhite">';
3908  print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Save").'">';
3909  print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
3910  print '</td>';
3911  } else {
3912  print '<td class="tdoverflowmax200">';
3913  print '<span title="'.dol_escape_htmltag($proptype).'">'.dol_escape_htmltag($proptype).'</span>';
3914  print '</td>';
3915  print '<td class="tdoverflowmax200">';
3916  if ($proparrayofkeyval) {
3917  print '<span title="'.dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE)).'">';
3918  print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
3919  print '</span>';
3920  }
3921  print '</td>';
3922  print '<td class="center">';
3923  print dol_escape_htmltag($propnotnull);
3924  print '</td>';
3925  print '<td>';
3926  print dol_escape_htmltag($propdefault);
3927  print '</td>';
3928  print '<td class="center">';
3929  print $propindex ? '1' : '';
3930  print '</td>';
3931  print '<td class="center">';
3932  print $propforeignkey ? dol_escape_htmltag($propforeignkey) : '';
3933  print '</td>';
3934  print '<td class="right">';
3935  print dol_escape_htmltag($propposition);
3936  print '</td>';
3937  print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
3938  print $propenabled ? dol_escape_htmltag($propenabled) : '';
3939  print '</td>';
3940  // Visibility
3941  print '<td class="center tdoverflowmax100" title="'.($propvisible ? dol_escape_htmltag($propvisible) : '0').'">';
3942  print $propvisible ? dol_escape_htmltag($propvisible) : '0';
3943  print '</td>';
3944  // Readonly
3945  print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
3946  print $propnoteditable ? dol_escape_htmltag($propnoteditable) : '';
3947  print '</td>';
3948  print '<td class="center">';
3949  print $propalwayseditable ? dol_escape_htmltag($propalwayseditable) : '';
3950  print '</td>';
3951  print '<td class="center">';
3952  print $propsearchall ? '1' : '';
3953  print '</td>';
3954  print '<td class="center">';
3955  print $propisameasure ? dol_escape_htmltag($propisameasure) : '';
3956  print '</td>';
3957  print '<td class="center tdoverflowmax100" title="'.($propcss ? dol_escape_htmltag($propcss) : '').'">';
3958  print $propcss ? dol_escape_htmltag($propcss) : '';
3959  print '</td>';
3960  print '<td class="center tdoverflowmax100" title="'.($propcssview ? dol_escape_htmltag($propcssview) : '').'">';
3961  print $propcssview ? dol_escape_htmltag($propcssview) : '';
3962  print '</td>';
3963  print '<td class="center tdoverflowmax100" title="'.($propcsslist ? dol_escape_htmltag($propcsslist) : '').'">';
3964  print $propcsslist ? dol_escape_htmltag($propcsslist) : '';
3965  print '</td>';
3966  // Key for tooltop
3967  print '<td class="tdoverflowmax150" title="'.($prophelp ? dol_escape_htmltag($prophelp) : '').'">';
3968  print $prophelp ? dol_escape_htmltag($prophelp) : '';
3969  print '</td>';
3970  print '<td class="center">';
3971  print $propshowoncombobox ? dol_escape_htmltag($propshowoncombobox) : '';
3972  print '</td>';
3973  /*print '<td class="center">';
3974  print $propdisabled?$propdisabled:'';
3975  print '</td>';*/
3976  print '<td class="center">';
3977  print $propvalidate ? dol_escape_htmltag($propvalidate) : '';
3978  print '</td>';
3979  print '<td class="tdoverflowmax200">';
3980  print '<span title="'.dol_escape_htmltag($propcomment).'">';
3981  print dol_escape_htmltag($propcomment);
3982  print '</span>';
3983  print '</td>';
3984  print '<td class="center tdstickyright tdstickyghostwhite">';
3985  if ($propname != 'rowid') {
3986  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>';
3987  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>';
3988  }
3989  print '</td>';
3990  }
3991  print '</tr>';
3992  }
3993  } else {
3994  if ($tab == 'specifications') {
3995  if ($action != 'editfile' || empty($file)) {
3996  print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
3997  print '<br>';
3998 
3999  $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
4000 
4001  foreach ($specs as $spec) {
4002  $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
4003  $format = 'asciidoc';
4004  if (preg_match('/\.md$/i', $spec['name'])) {
4005  $format = 'markdown';
4006  }
4007  print '<span class="fa fa-file-o"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4008  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>';
4009  print '<br>';
4010  }
4011  } else {
4012  // Use MD or asciidoc
4013 
4014  //print $langs->trans("UseAsciiDocFormat").'<br>';
4015 
4016  $fullpathoffile = dol_buildpath($file, 0);
4017 
4018  $content = file_get_contents($fullpathoffile);
4019 
4020  // New module
4021  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4022  print '<input type="hidden" name="token" value="'.newToken().'">';
4023  print '<input type="hidden" name="action" value="savefile">';
4024  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4025  print '<input type="hidden" name="tab" value="'.$tab.'">';
4026  print '<input type="hidden" name="module" value="'.$module.'">';
4027 
4028  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4029  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4030  print '<br>';
4031  print '<center>';
4032  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4033  print ' &nbsp; ';
4034  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4035  print '</center>';
4036 
4037  print '</form>';
4038  }
4039  }
4040  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>';
4041  }
4042  print '</table>';
4043  print '</div>';
4044 
4045  print '</form>';
4046  } else {
4047  print '<span class="warning">'.$langs->trans('Failed to init the object with the new '.$tabobj.'($db)').'</warning>';
4048  }
4049  } catch (Exception $e) {
4050  print $e->getMessage();
4051  }
4052  } else {
4053  if (empty($forceddirread)) {
4054  $fullpathoffile = dol_buildpath($file, 0);
4055  } else {
4056  $fullpathoffile = $dirread.'/'.$file;
4057  }
4058 
4059  $content = file_get_contents($fullpathoffile);
4060 
4061  // New module
4062  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4063  print '<input type="hidden" name="token" value="'.newToken().'">';
4064  print '<input type="hidden" name="action" value="savefile">';
4065  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4066  print '<input type="hidden" name="tab" value="'.$tab.'">';
4067  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4068  print '<input type="hidden" name="module" value="'.$module.($forceddirread ? '@'.$dirread : '').'">';
4069 
4070  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4071  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4072  print '<br>';
4073  print '<center>';
4074  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4075  print ' &nbsp; ';
4076  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4077  print '</center>';
4078 
4079  print '</form>';
4080  }
4081  }
4082 
4083  print dol_get_fiche_end(); // Level 3
4084  }
4085 
4086  if ($tab == 'dictionaries') {
4087  print '<!-- tab=dictionaries -->'."\n";
4088  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4089 
4090  $dicts = $moduleobj->dictionaries;
4091 
4092  if ($action != 'editfile' || empty($file)) {
4093  print '<span class="opacitymedium">';
4094  $htmlhelp = $langs->trans("DictionariesDefDescTooltip", '{s1}');
4095  $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/dict.php">'.$langs->trans('Setup').' - '.$langs->trans('Dictionaries').'</a>', $htmlhelp);
4096  print $form->textwithpicto($langs->trans("DictionariesDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
4097  print '</span>';
4098  print '<br>';
4099 
4100  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4101  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>';
4102  print '<br>';
4103  if (is_array($dicts) && !empty($dicts)) {
4104  print '<span class="fa fa-file-o"></span> '.$langs->trans("LanguageFile").' :</span> ';
4105  print '<strong class="wordbreak">'.$dicts['langs'].'</strong>';
4106  print '<br>';
4107  }
4108 
4109  print '<!-- tab=objects -->'."\n";
4110  $head3 = array();
4111  $h = 0;
4112 
4113  // Dir for module
4114  //$dir = $dirread.'/'.$modulelowercase.'/class';
4115 
4116  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=newdictionary';
4117  $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewDictionary").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
4118  $head3[$h][2] = 'newdictionary';
4119  $h++;
4120 
4121  // Scan for object class files
4122  //$listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
4123 
4124  $firstdicname = '';
4125  if (!empty($dicts['tabname'])) {
4126  foreach ($dicts['tabname'] as $key => $dic) {
4127  $dicname = $dic;
4128  $diclabel = $dicts['tablib'][$key];
4129 
4130  if (empty($firstdicname)) {
4131  $firstdicname = $dicname;
4132  }
4133 
4134  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic='.$dicname;
4135  $head3[$h][1] = $diclabel;
4136  $head3[$h][2] = $dicname;
4137  $h++;
4138  }
4139  }
4140 
4141  if ($h > 1) {
4142  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=deletedictionary';
4143  $head3[$h][1] = $langs->trans("DangerZone");
4144  $head3[$h][2] = 'deletedictionary';
4145  $h++;
4146  }
4147 
4148  // 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.
4149  if ($tabdic == 'newdicifnodic') {
4150  if ($firstdicname) {
4151  $tabdic = $firstdicname;
4152  } else {
4153  $tabdic = 'newdictionary';
4154  }
4155  }
4156 
4157  print load_fiche_titre($langs->trans("ListOfDictionariesEntries"), '', '');
4158 
4159  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4160  print '<input type="hidden" name="token" value="'.newToken().'">';
4161  print '<input type="hidden" name="action" value="addproperty">';
4162  print '<input type="hidden" name="tab" value="dictionaries">';
4163  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4164  print '<input type="hidden" name="tabdic" value="'.dol_escape_htmltag($tabdic).'">';
4165 
4166  print '<div class="div-table-responsive">';
4167  print '<table class="noborder">';
4168 
4169  print '<tr class="liste_titre">';
4170  print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'thsticky thstickygrey ');
4171  print_liste_field_titre("Table", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4172  print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4173  print_liste_field_titre("SQL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4174  print_liste_field_titre("SQLSort", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4175  print_liste_field_titre("FieldsView", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4176  print_liste_field_titre("FieldsEdit", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4177  print_liste_field_titre("FieldsInsert", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4178  print_liste_field_titre("Rowid", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4179  print_liste_field_titre("Condition", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4180  print "</tr>\n";
4181 
4182  if (!empty($dicts) && is_array($dicts) && !empty($dicts['tabname']) && is_array($dicts['tabname'])) {
4183  $i = 0;
4184  $maxi = count($dicts['tabname']);
4185  while ($i < $maxi) {
4186  print '<tr class="oddeven">';
4187 
4188  print '<td class="tdsticky tdstickygray">';
4189  print ($i + 1);
4190  print '</td>';
4191 
4192  print '<td>';
4193  print $dicts['tabname'][$i];
4194  print '</td>';
4195 
4196  print '<td>';
4197  print $dicts['tablib'][$i];
4198  print '</td>';
4199 
4200  print '<td>';
4201  print $dicts['tabsql'][$i];
4202  print '</td>';
4203 
4204  print '<td>';
4205  print $dicts['tabsqlsort'][$i];
4206  print '</td>';
4207 
4208  print '<td>';
4209  print $dicts['tabfield'][$i];
4210  print '</td>';
4211 
4212  print '<td>';
4213  print $dicts['tabfieldvalue'][$i];
4214  print '</td>';
4215 
4216  print '<td>';
4217  print $dicts['tabfieldinsert'][$i];
4218  print '</td>';
4219 
4220  print '<td class="right">';
4221  print $dicts['tabrowid'][$i];
4222  print '</td>';
4223 
4224  print '<td class="right">';
4225  print $dicts['tabcond'][$i];
4226  print '</td>';
4227 
4228  print '</tr>';
4229  $i++;
4230  }
4231  } else {
4232  print '<tr><td colspan="10"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
4233  }
4234 
4235  print '</table>';
4236  print '</div>';
4237 
4238  print '</form>';
4239 
4240  print dol_get_fiche_head($head3, $tabdic, '', -1, ''); // Level 3
4241 
4242  if ($tabdic == 'newdictionary') {
4243  // New dic tab
4244  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4245  print '<input type="hidden" name="token" value="'.newToken().'">';
4246  print '<input type="hidden" name="action" value="initdic">';
4247  print '<input type="hidden" name="tab" value="dictionaries">';
4248  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4249 
4250  print '<span class="opacitymedium">'.$langs->trans("EnterNameOfDictionaryDesc").'</span><br><br>';
4251 
4252  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>';
4253  //print '<input type="checkbox" name="includerefgeneration" id="includerefgeneration" value="includerefgeneration"> <label for="includerefgeneration">'.$form->textwithpicto($langs->trans("IncludeRefGeneration"), $langs->trans("IncludeRefGenerationHelp")).'</label><br>';
4254  //print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
4255  print '<input type="submit" class="button smallpaddingimp" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4256  /*print '<br>';
4257  print '<br>';
4258  print '<br>';
4259  print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
4260  print '<br>';
4261  print '<br>';
4262  //print '<input type="checkbox" name="initfromtablecheck"> ';
4263  print $langs->trans("InitStructureFromExistingTable");
4264  print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
4265  print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4266  print '<br>';
4267  */
4268  print '</form>';
4269  } elseif ($tabdic == 'deletedictionary') {
4270  // Delete dic tab
4271  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4272  print '<input type="hidden" name="token" value="'.newToken().'">';
4273  print '<input type="hidden" name="action" value="confirm_deleteobject">';
4274  print '<input type="hidden" name="tab" value="dictionaries">';
4275  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4276 
4277  print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
4278 
4279  print '<input type="text" name="objectname" value="'.dol_escape_htmltag($modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'">';
4280  print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
4281  print '</form>';
4282  } else {
4283  print $langs->trans("FeatureNotYetAvailable");
4284  }
4285 
4286  print dol_get_fiche_end();
4287  } else {
4288  $fullpathoffile = dol_buildpath($file, 0);
4289 
4290  $content = file_get_contents($fullpathoffile);
4291 
4292  // New module
4293  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4294  print '<input type="hidden" name="token" value="'.newToken().'">';
4295  print '<input type="hidden" name="action" value="savefile">';
4296  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4297  print '<input type="hidden" name="tab" value="'.$tab.'">';
4298  print '<input type="hidden" name="module" value="'.$module.'">';
4299 
4300  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4301  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4302  print '<br>';
4303  print '<center>';
4304  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4305  print ' &nbsp; ';
4306  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4307  print '</center>';
4308 
4309  print '</form>';
4310  }
4311  }
4312 
4313  if ($tab == 'menus') {
4314  print '<!-- tab=menus -->'."\n";
4315  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4316  $dirins = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
4317  $destdir = $dirins.'/'.strtolower($module);
4318  $listofobject = dol_dir_list($destdir.'/class', 'files', 0, '\.class\.php$');
4319  $objects = dolGetListOfObjectclasses($destdir);
4320 
4321  $leftmenus = array();
4322 
4323  $menus = $moduleobj->menu;
4324 
4325  if ($action == 'deletemenu') {
4326  $formconfirms = $form->formconfirm(
4327  $_SERVER["PHP_SELF"].'?menukey='.urlencode(GETPOST('menukey', 'int')).'&tab='.urlencode($tab).'&module='.urlencode($module),
4328  $langs->trans('Delete'),
4329  $langs->trans('Confirm Delete Menu', GETPOST('menukey', 'int')),
4330  'confirm_deletemenu',
4331  '',
4332  0,
4333  1
4334  );
4335  print $formconfirms;
4336  }
4337  if ($action != 'editfile' || empty($file)) {
4338  print '<span class="opacitymedium">';
4339  $htmlhelp = $langs->trans("MenusDefDescTooltip", '{s1}');
4340  $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);
4341  print $form->textwithpicto($langs->trans("MenusDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
4342  print '</span>';
4343  print '<br>';
4344 
4345  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4346  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>';
4347  print '<br>';
4348 
4349  print '<br>';
4350  print load_fiche_titre($langs->trans("ListOfMenusEntries"), '', '');
4351 
4352  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4353  print '<input type="hidden" name="token" value="'.newToken().'">';
4354  print '<input type="hidden" name="action" value="addmenu">';
4355  print '<input type="hidden" name="tab" value="menus">';
4356  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4357  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4358 
4359  print '<div class="div-table-responsive">';
4360  print '<table class="noborder small">';
4361 
4362  print '<tr class="liste_titre">';
4363  print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ');
4364  print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4365  print_liste_field_titre("Title", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center');
4366  print_liste_field_titre("LinkToParentMenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4367  print_liste_field_titre("mainmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4368  print_liste_field_titre("leftmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4369  print_liste_field_titre("URL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->transnoentitiesnoconv('DetailUrl'));
4370  print_liste_field_titre("LanguageFile", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4371  print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'right ');
4372  print_liste_field_titre("Enabled", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans('DetailEnabled'));
4373  print_liste_field_titre("Rights", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailRight'));
4374  print_liste_field_titre("Target", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailTarget'));
4375  print_liste_field_titre("MenuForUsers", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans('DetailUser'));
4376  print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans(''));
4377 
4378  print "</tr>\n";
4379  $r = count($menus)+1;
4380  // for adding menu on module
4381  print '<tr>';
4382  print '<td class="center"><input type="hidden" readonly class="center maxwidth50" name="propenabled" value="#"></td>';
4383  print '<td class="center">';
4384  print '<select class="center maxwidth50" name="type">';
4385  print '<option value="">'.$langs->trans("........").'</option><option value="'.dol_escape_htmltag("left").'">left</option><option value="'.dol_escape_htmltag("top").'">top</option>';
4386  print '</select></td>';
4387  print '<td class="left"><input type="text" class="left maxwidth100" name="titre" value="'.dol_escape_htmltag(GETPOST('titre', 'alpha')).'"></td>';
4388  print '<td class="left">';
4389  print '<select name="fk_menu">';
4390  print '<option value="">'.$langs->trans("........").'</option>';
4391  foreach ($menus as $obj) {
4392  if ($obj['type'] == 'left' && !empty($obj['leftmenu'])) {
4393  print "<option value=".strtolower($obj['leftmenu']).">".$obj['leftmenu']."</option>";
4394  }
4395  }
4396  print '</select>';
4397  print '</td>';
4398  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>';
4399  print '<td class="center"><input type="text" class="left maxwidth" name="leftmenu" value="'.dol_escape_htmltag(GETPOST('leftmenu', 'alpha')).'"></td>';
4400  print '<td class="left"><input type="text" class="left maxwidth" name="url" value="'.dol_escape_htmltag(GETPOST('url', 'alpha')).'"></td>';
4401  print '<td class="left"><input type="text" class="left maxwidth" name="langs" value="'.strtolower($module).'@'.strtolower($module).'" readonly></td>';
4402  print '<td class="center"><input type="text" class="center maxwidth50 tdstickygray" name="position" value="'.(1000+$r).'" readonly></td>';
4403  print '<td class="center">';
4404  print '<select class="center maxwidth" name="enabled">';
4405  print '<option value="1" selected>'.$langs->trans("Show").'</option>';
4406  print '<option value="0">'.$langs->trans("Hide").'</option>';
4407  print '</select>';
4408  print '</td>';
4409  print '<td class="center">';
4410  print '<select class="center maxwidth" name="perms">';
4411  print '<option selected value="1">'.$langs->trans("Yes").'</option>';
4412  print '<option value="0">'.$langs->trans("No").'</option>';
4413  print '</select>';
4414  print '</td>';
4415  print '<td class="center"><input type="text" class="center maxwidth50" name="target" value="'.dol_escape_htmltag(GETPOST('target', 'alpha')).'"></td>';
4416  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>';
4417 
4418  print '<td class="center tdstickyright tdstickyghostwhite">';
4419  print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
4420  print '</td>';
4421  print '</tr>';
4422  // end form for add menu
4423  if (count($menus)) {
4424  $i = 0;
4425  foreach ($menus as $menu) {
4426  $i++;
4427  //for get parent in menu
4428  $string = dol_escape_htmltag($menu['fk_menu']);
4429  $value = substr($string, strpos($string, 'fk_leftmenu=') + strlen('fk_leftmenu='));
4430 
4431  $propFk_menu = !empty($menu['fk_menu']) ? $menu['fk_menu'] : GETPOST('fk_menu');
4432  $propTitre = !empty($menu['titre']) ? $menu['titre'] : GETPOST('titre');
4433  $propMainmenu = !empty($menu['mainmenu']) ? $menu['mainmenu'] : GETPOST('mainmenu');
4434  $propLeftmenu = !empty($menu['leftmenu']) ? $menu['leftmenu'] : GETPOST('leftmenu');
4435  $propUrl = !empty($menu['url']) ? $menu['url'] : GETPOST('url', 'alpha');
4436  $propPerms = empty($menu['perms']) ? $menu['perms'] : GETPOST('perms');
4437  $propUser = !empty($menu['user']) ? $menu['user'] : GETPOST('user');
4438  $propTarget = !empty($menu['target']) ? $menu['target'] : GETPOST('target');
4439  $propEnabled = empty($menu['enabled']) ? $menu['enabled'] : GETPOST('enabled');
4440  if ($action == 'editmenu' && GETPOST('menukey', 'int') == $i) {
4441  //var_dump($propFk_menu);exit;
4442  print '<tr class="oddeven">';
4443  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4444  print '<input type="hidden" name="token" value="'.newToken().'">';
4445  print '<input type="hidden" name="action" value="modify_menu">';
4446  print '<input type="hidden" name="tab" value="menus">';
4447  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4448  print '<input type="hidden" name="tabobject" value="'.dol_escape_htmltag($tabobject).'">';
4449  print '<td class="tdsticky tdstickygray">';
4450  print $i;
4451  print '</td>';
4452  print '<input type="hidden" name="menukey" value="'.$i.'"/>';
4453  print '<td class="center">
4454  <select class="center maxwidth50" name="type">
4455  <option value="'.dol_escape_htmltag($menu['type']).'">
4456  '.dol_escape_htmltag($menu['type']).'
4457  </option>';
4458  print '<option value="'.($menu['type'] == 'left' ? 'top' : 'left').'">';
4459  if ($menu['type'] == 'left') {
4460  print 'top';
4461  } else {
4462  print 'left';
4463  }
4464  print '</option></select></td>';
4465  print '<td class="left"><input type="text" class="left maxwidth" name="titre" value="'.dol_escape_htmltag($propTitre).'"></td>';
4466  print '<td class="left">';
4467  print '<select name="fk_menu" class="left maxwidth">';
4468  print '<option value="'.dol_escape_htmltag($propFk_menu).'">'.dol_escape_htmltag($value).'</option>';
4469  foreach ($menus as $obj) {
4470  if ($obj['type'] == 'left' && $obj['leftmenu'] != $value && $obj['leftmenu'] != $menu['leftmenu']) {
4471  print "<option value=".strtolower($obj['leftmenu']).">".$obj['leftmenu']."</option>";
4472  }
4473  }
4474  print '</select>';
4475  print '</td>';
4476  print '<td class="left"><input type="text" class="left maxwidth75" name="mainmenu" value="'.dol_escape_htmltag($propMainmenu).'" readonly></td>';
4477  print '<td class="left"><input type="text" class="left maxwidth" name="leftmenu" value="'.dol_escape_htmltag($propLeftmenu).'"></td>';
4478  print '<td class="left"><input type="text" class="left maxwidth" name="url" value="'.dol_escape_htmltag($propUrl).'"></td>';
4479  print '<td class="left"><input type="text" class="left maxwidth" name="langs" value="'.strtolower($module).'@'.strtolower($module).'" readonly></td>';
4480  print '<td class="center"><input type="text" class="center maxwidth50 tdstickygray" name="position" value="'.(1000+$r-1).'" readonly></td>';
4481  print '<td class="left">';
4482  print '<select class="center maxwidth" name="enabled">';
4483  print '<option value="'.dol_escape_htmltag($propEnabled).'">'.(dol_escape_htmltag($propEnabled) == '0' ? $langs->trans('Hide') : $langs->trans('Show')).'</option>';
4484  if ($propEnabled != '0') {
4485  print '<option value="0" >'.$langs->trans("Hide").'</option>';
4486  } else {
4487  print '<option value="1">'.$langs->trans("Show").'</option>';
4488  }
4489  print '</select>';
4490  print '</td>';
4491  print '<td class="center">';
4492  print '<select class="center maxwidth" name="perms">';
4493  print '<option selected value="'.dol_escape_htmltag($propPerms).'">'.(dol_escape_htmltag($propPerms) == '0' ? $langs->trans('No') : $langs->trans('Yes')).'</option>';
4494  if ($propPerms != '0') {
4495  print '<option value="0">'.$langs->trans("No").'</option>';
4496  } else {
4497  print '<option value="1">'.$langs->trans("Yes").'</option>';
4498  }
4499  print '</select>';
4500  print '</td>';
4501  print '<td class="center"><input type="text" class="center maxwidth50" name="target" value="'.dol_escape_htmltag($propTarget).'"></td>';
4502  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>';
4503  print '<td class="center tdstickyright tdstickyghostwhite maxwidth50">';
4504  print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Modify").'">';
4505  print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
4506  print '</td>';
4507  print '</form>';
4508  print '</tr>';
4509  } else {
4510  print '<tr class="oddeven">';
4511 
4512  print '<td class="tdsticky tdstickygray">';
4513  print $i;
4514  print '</td>';
4515 
4516  print '<td>';
4517  print dol_escape_htmltag($menu['type']);
4518  print '</td>';
4519 
4520  print '<td>';
4521  print dol_escape_htmltag($menu['titre']);
4522  print '</td>';
4523 
4524  print '<td>';
4525  print ($value == strtolower($module) ? '/' : $value);
4526  print '</td>';
4527 
4528  print '<td>';
4529  print dol_escape_htmltag($menu['mainmenu']);
4530  print '</td>';
4531 
4532  print '<td>';
4533  print dol_escape_htmltag($menu['leftmenu']);
4534  print '</td>';
4535 
4536  print '<td class="tdoverflowmax300" title="'.dol_escape_htmltag($menu['url']).'">';
4537  print dol_escape_htmltag($menu['url']);
4538  print '</td>';
4539 
4540  print '<td>';
4541  print dol_escape_htmltag($menu['langs']);
4542  print '</td>';
4543 
4544  print '<td class="center">';
4545  print dol_escape_htmltag($menu['position']);
4546  print '</td>';
4547 
4548  print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['enabled']).'">';
4549  print (dol_escape_htmltag($menu['enabled']) == '0' ? $langs->trans("Hide") : $langs->trans("Show"));
4550  print '</td>';
4551 
4552  print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['perms']).'">';
4553  print (dol_escape_htmltag($menu['perms'])== '1' ? $langs->trans("Yes") : $langs->trans("No"));
4554  print '</td>';
4555 
4556  print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['target']).'">';
4557  print dol_escape_htmltag($menu['target']);
4558  print '</td>';
4559 
4560  print '<td class="center">';
4561  if ($menu['user'] == 2) {
4562  print $langs->trans("AllMenus");
4563  } elseif ($menu['user'] == 0) {
4564  print $langs->trans('Internal');
4565  } elseif ($menu['user'] == 1) {
4566  print $langs->trans('External');
4567  } else {
4568  print $menu['user']; // should not happen
4569  }
4570  print '</td>';
4571  print '<td class="center tdstickyright tdstickyghostwhite">';
4572  if ($menu['titre'] != 'Module'.$module.'Name') {
4573  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>';
4574  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>';
4575  }
4576  print '</td>';
4577  }
4578  print '</tr>';
4579  }
4580  } else {
4581  print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
4582  }
4583 
4584  print '</table>';
4585  print '</div>';
4586 
4587  print '</form>';
4588  } else {
4589  $fullpathoffile = dol_buildpath($file, 0);
4590 
4591  $content = file_get_contents($fullpathoffile);
4592 
4593  // New module
4594  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4595  print '<input type="hidden" name="token" value="'.newToken().'">';
4596  print '<input type="hidden" name="action" value="savefile">';
4597  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4598  print '<input type="hidden" name="tab" value="'.$tab.'">';
4599  print '<input type="hidden" name="module" value="'.$module.'">';
4600 
4601  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4602  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4603  print '<br>';
4604  print '<center>';
4605  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4606  print ' &nbsp; ';
4607  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4608  print '</center>';
4609 
4610  print '</form>';
4611  }
4612  }
4613 
4614  if ($tab == 'permissions') {
4615  print '<!-- tab=permissions -->'."\n";
4616  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4617 
4618  $perms = $moduleobj->rights;
4619 
4620  // Get list of existing objects
4621  $dir = $dirread.'/'.$modulelowercase.'/class';
4622  $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
4623  $objects = array('myobject');
4624  $reg =array();
4625  foreach ($listofobject as $fileobj) {
4626  $tmpcontent = file_get_contents($fileobj['fullname']);
4627  if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
4628  $objects[$fileobj['fullname']] = $reg[1];
4629  }
4630  }
4631 
4632  // declared select list for actions and labels permissions
4633  $crud = array('read'=>'CRUDRead', 'write'=>'CRUDCreateWrite', 'delete'=>'Delete');
4634  $labels = array("Read objects of ".$module, "Create/Update objects of ".$module, "Delete objects of ".$module);
4635 
4636  $action = GETPOST('action', 'alpha');
4637 
4638  if ($action == 'deleteright') {
4639  $formconfirm = $form->formconfirm(
4640  $_SERVER["PHP_SELF"].'?permskey='.urlencode(GETPOST('permskey', 'int')).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj),
4641  $langs->trans('Delete'),
4642  $langs->trans('Confirm Delete Right', GETPOST('permskey', 'alpha')),
4643  'confirm_deleteright',
4644  '',
4645  0,
4646  1
4647  );
4648  print $formconfirm;
4649  }
4650 
4651  if ($action != 'editfile' || empty($file)) {
4652  print '<!-- Tab to manage permissions -->'."\n";
4653  print '<span class="opacitymedium">';
4654  $htmlhelp = $langs->trans("PermissionsDefDescTooltip", '{s1}');
4655  $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/perms.php">'.$langs->trans('DefaultRights').'</a>', $htmlhelp);
4656  print $form->textwithpicto($langs->trans("PermissionsDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
4657  print '</span>';
4658  print '<br>';
4659 
4660  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4661  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>';
4662  print '<br>';
4663 
4664  print '<br>';
4665  print load_fiche_titre($langs->trans("ListOfPermissionsDefined"), '', '');
4666 
4667  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4668  print '<input type="hidden" name="token" value="'.newToken().'">';
4669  print '<input type="hidden" name="action" value="addright">';
4670  print '<input type="hidden" name="tab" value="permissions">';
4671  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4672  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4673 
4674  print '<div class="div-table-responsive">';
4675  print '<table class="noborder">';
4676 
4677  print '<tr class="liste_titre">';
4678  print_liste_field_titre("ID", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
4679  print_liste_field_titre("Object", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
4680  print_liste_field_titre("CRUD", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
4681  print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
4682  print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, "center");
4683  print "</tr>\n";
4684 
4685  //form for add new right
4686  print '<tr class="small">';
4687  print '<td><input type="hidden" readonly name="id" class="width75" value="0"></td>';
4688 
4689  print '<td><select class="minwidth100" name="permissionObj" id="permissionObj">';
4690  print '<option value=""></option>';
4691  foreach ($objects as $obj) {
4692  if ($obj != 'myobject') {
4693  print '<option value="'.$obj.'">'.$obj.'</option>';
4694  }
4695  }
4696  print '</select></td>';
4697 
4698  print '<td><select class="maxwidth" name="crud" id="crud">';
4699  print '<option value=""></option>';
4700  foreach ($crud as $key => $val) {
4701  print '<option value="'.$key.'">'.$langs->trans($val).'</option>';
4702  }
4703  print '</td>';
4704 
4705  print '<td >';
4706  print '<input type="text" name="label" id="label" class="minwidth200">';
4707  print '</td>';
4708 
4709  print '<td class="center tdstickyright tdstickyghostwhite">';
4710  print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
4711  print '</td>';
4712  print '</tr>';
4713 
4714  if (count($perms)) {
4715  $i = 0;
4716  foreach ($perms as $perm) {
4717  $i++;
4718 
4719  // section for editing right
4720  if ($action == 'edit_right' && $perm[0] == (int) GETPOST('permskey', 'int')) {
4721  print '<tr class="oddeven">';
4722  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="modifPerms">';
4723  print '<input type="hidden" name="token" value="'.newToken().'">';
4724  print '<input type="hidden" name="tab" value="permissions">';
4725  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4726  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4727  print '<input type="hidden" name="action" value="update_right">';
4728  print '<input type="hidden" name="counter" value="'.$i.'">';
4729 
4730  print '<input type="hidden" name="permskey" value="'.$perm[0].'">';
4731 
4732  print '<td class="tdsticky tdstickygray">';
4733  print '<input class="width75" type="text" readonly value="'.dol_escape_htmltag($perm[0]).'"/>';
4734  print '</td>';
4735 
4736  print '<td>';
4737  print '<select name="crud">';
4738  print '<option value="'.dol_escape_htmltag($perm[5]).'">'.$langs->trans($perm[5]).'</option>';
4739  foreach ($crud as $i=> $x) {
4740  if ($perm[5] != $i) {
4741  print '<option value="'.$i.'">'.$langs->trans(ucfirst($x)).'</option>';
4742  }
4743  }
4744  print '</select>';
4745  print '</td>';
4746 
4747  print '<td><select name="permissionObj" >';
4748  print '<option value="'.dol_escape_htmltag($perm[4]).'">'.ucfirst($perm[4]).'</option>';
4749  print '</select></td>';
4750 
4751  print '<td>';
4752  print '<input type="text" name="label" value="'.dol_escape_htmltag($perm[1]).'">';
4753  print '</td>';
4754 
4755  print '<td class="center tdstickyright tdstickyghostwhite">';
4756  print '<input id ="modifyPerm" class="reposition button smallpaddingimp" type="submit" name="modifyright" value="'.$langs->trans("Modify").'"/>';
4757  print '<br>';
4758  print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'"/>';
4759  print '</td>';
4760 
4761  print '</form>';
4762  print '</tr>';
4763  } else {
4764  // $perm can be module->object->crud or module->crud
4765  print '<tr class="oddeven">';
4766 
4767  print '<td>';
4768  print dol_escape_htmltag($perm[0]);
4769  print '</td>';
4770 
4771  print '<td>';
4772  if (in_array($perm[5], array('lire', 'read', 'creer', 'write', 'effacer', 'delete'))) {
4773  print dol_escape_htmltag(ucfirst($perm[4]));
4774  } else {
4775  print ''; // No particular object
4776  }
4777  print '</td>';
4778 
4779  print '<td>';
4780  if (in_array($perm[5], array('lire', 'read', 'creer', 'write', 'effacer', 'delete'))) {
4781  print ucfirst($langs->trans($perm[5]));
4782  } else {
4783  print ucfirst($langs->trans($perm[4]));
4784  }
4785  print '</td>';
4786 
4787  print '<td>';
4788  print $langs->trans($perm[1]);
4789  print '</td>';
4790 
4791  print '<td class="center tdstickyright tdstickyghostwhite">';
4792  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>';
4793  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>';
4794 
4795  print '</td>';
4796 
4797  print '</tr>';
4798  }
4799  }
4800  } else {
4801  print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
4802  }
4803 
4804  print '</table>';
4805  print '</div>';
4806 
4807  print '</form>';
4808  print '<script>
4809  function updateInputField() {
4810  value1 = $("#crud").val();
4811  value2 = $("#permissionObj").val();
4812 
4813  // VĂ©rifie si les deux sĂ©lections sont faites
4814  if ($("#label").val() == "" && value1 && value2) {
4815  switch(value1.toLowerCase()){
4816  case "read":
4817  $("#label").val("Read "+value2+" object of '.ucfirst($module).'")
4818  break;
4819  case "write":
4820  $("#label").val("Create/Update "+value2+" object of '.ucfirst($module).'")
4821  break;
4822  case "delete":
4823  $("#label").val("Delete "+value2+" object of '.ucfirst($module).'")
4824  break;
4825  default:
4826  $("#label").val("")
4827  }
4828  }
4829  }
4830 
4831  $("#crud, #permissionObj").change(updateInputField);
4832  updateInputField();
4833  </script>';
4834  } else {
4835  $fullpathoffile = dol_buildpath($file, 0);
4836 
4837  $content = file_get_contents($fullpathoffile);
4838 
4839  // New module
4840  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4841  print '<input type="hidden" name="token" value="'.newToken().'">';
4842  print '<input type="hidden" name="action" value="savefile">';
4843  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4844  print '<input type="hidden" name="tab" value="'.$tab.'">';
4845  print '<input type="hidden" name="module" value="'.$module.'">';
4846 
4847  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4848  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4849  print '<br>';
4850  print '<center>';
4851  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4852  print ' &nbsp; ';
4853  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4854  print '</center>';
4855 
4856  print '</form>';
4857  }
4858  }
4859 
4860  if ($tab == 'hooks') {
4861  print '<!-- tab=hooks -->'."\n";
4862  if ($action != 'editfile' || empty($file)) {
4863  print '<span class="opacitymedium">'.$langs->trans("HooksDefDesc").'</span><br>';
4864  print '<br>';
4865 
4866  print '<table>';
4867 
4868  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4869  print '<tr><td>';
4870  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4871  print '</td><td>';
4872  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>';
4873  print '</td></tr>';
4874 
4875  print '<tr><td>';
4876  $pathtohook = strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
4877  print '<span class="fa fa-file-o"></span> '.$langs->trans("HooksFile").' : ';
4878  if (dol_is_file($dirins.'/'.$pathtohook)) {
4879  print '<strong class="wordbreak">'.$pathtohook.'</strong>';
4880  print '</td>';
4881  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> ';
4882  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>';
4883  } else {
4884  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4885  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>';
4886  print '<td></td>';
4887  }
4888  print '</tr>';
4889  } else {
4890  $fullpathoffile = dol_buildpath($file, 0);
4891 
4892  $content = file_get_contents($fullpathoffile);
4893 
4894  // New module
4895  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4896  print '<input type="hidden" name="token" value="'.newToken().'">';
4897  print '<input type="hidden" name="action" value="savefile">';
4898  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4899  print '<input type="hidden" name="tab" value="'.$tab.'">';
4900  print '<input type="hidden" name="module" value="'.$module.'">';
4901 
4902  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4903  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4904  print '<br>';
4905  print '<center>';
4906  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4907  print ' &nbsp; ';
4908  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4909  print '</center>';
4910 
4911  print '</form>';
4912  }
4913  }
4914 
4915  if ($tab == 'triggers') {
4916  print '<!-- tab=triggers -->'."\n";
4917  require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
4918 
4919  $interfaces = new Interfaces($db);
4920  $triggers = $interfaces->getTriggersList(array('/'.strtolower($module).'/core/triggers'));
4921 
4922  if ($action != 'editfile' || empty($file)) {
4923  print '<span class="opacitymedium">'.$langs->trans("TriggerDefDesc").'</span><br>';
4924  print '<br>';
4925 
4926  print '<table>';
4927 
4928  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4929  print '<tr><td>';
4930  print '<span class="fa fa-file-o"></span> '.$langs->trans(