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