dolibarr  x.y.z
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 $tmpdirread) {
139  $moduletype = 'external';
140  if ($tmpdirread == DOL_DOCUMENT_ROOT) {
141  $moduletype = 'internal';
142  }
143 
144  $dirsincustom = dol_dir_list($tmpdirread, 'directories');
145  if (is_array($dirsincustom) && count($dirsincustom) > 0) {
146  foreach ($dirsincustom as $dircustomcursor) {
147  $fullname = $dircustomcursor['fullname'];
148  if (dol_is_file($fullname.'/'.$FILEFLAG)) {
149  // Get real name of module (MyModule instead of mymodule)
150  $dirtoscanrel = basename($fullname).'/core/modules/';
151 
152  $descriptorfiles = dol_dir_list(dirname($fullname).'/'.$dirtoscanrel, 'files', 0, 'mod.*\.class\.php$');
153  if (empty($descriptorfiles)) { // If descriptor not found into module dir, we look into main module dir.
154  $dirtoscanrel = 'core/modules/';
155  $descriptorfiles = dol_dir_list($fullname.'/../'.$dirtoscanrel, 'files', 0, 'mod'.strtoupper(basename($fullname)).'\.class\.php$');
156  }
157  $modulenamewithcase = '';
158  $moduledescriptorrelpath = '';
159  $moduledescriptorfullpath = '';
160 
161  foreach ($descriptorfiles as $descriptorcursor) {
162  $modulenamewithcase = preg_replace('/^mod/', '', $descriptorcursor['name']);
163  $modulenamewithcase = preg_replace('/\.class\.php$/', '', $modulenamewithcase);
164  $moduledescriptorrelpath = $dirtoscanrel.$descriptorcursor['name'];
165  $moduledescriptorfullpath = $descriptorcursor['fullname'];
166  //var_dump($descriptorcursor);
167  }
168  if ($modulenamewithcase) {
169  $listofmodules[$dircustomcursor['name']] = array(
170  'modulenamewithcase'=>$modulenamewithcase,
171  'moduledescriptorrelpath'=> $moduledescriptorrelpath,
172  'moduledescriptorfullpath'=>$moduledescriptorfullpath,
173  'moduledescriptorrootpath'=>$tmpdirread,
174  'moduletype'=>$moduletype
175  );
176  }
177  //var_dump($listofmodules);
178  }
179  }
180  }
181 
182  if ($forceddirread && empty($listofmodules)) { // $forceddirread is 1 if we forced dir to read with dirins=... or with module=...@mydir
183  $listofmodules[strtolower($module)] = array(
184  'modulenamewithcase'=>$module,
185  'moduledescriptorrelpath'=> 'notyetimplemented',
186  'moduledescriptorfullpath'=> 'notyetimplemented',
187  'moduledescriptorrootpath'=> 'notyetimplemented',
188  );
189  }
190 
191  // Show description of content
192  $newdircustom = $dirins;
193  if (empty($newdircustom)) {
194  $newdircustom = img_warning();
195  }
196  // If dirread was forced to somewhere else, by using URL
197  // htdocs/modulebuilder/index.php?module=Inventory@/home/ldestailleur/git/dolibarr/htdocs/product
198  if (empty($i)) {
199  $textforlistofdirs .= $langs->trans("DirScanned").' : ';
200  } else {
201  $textforlistofdirs .= ', ';
202  }
203  $textforlistofdirs .= '<strong class="wordbreakimp">'.$tmpdirread.'</strong>';
204  if ($tmpdirread == DOL_DOCUMENT_ROOT) {
205  if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
206  $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MAIN_FEATURES_LEVEL"));
207  }
208  if (getDolGlobalString('MODULEBUILDER_ADD_DOCUMENT_ROOT')) {
209  $textforlistofdirs .= $form->textwithpicto('', $langs->trans("ConstantIsOn", "MODULEBUILDER_ADD_DOCUMENT_ROOT"));
210  }
211  }
212  $i++;
213 }
214 
215 
216 /*
217  * Actions
218  */
219 
220 if ($dirins && $action == 'initmodule' && $modulename) {
221  $modulename = ucfirst($modulename); // Force first letter in uppercase
222 
223  if (preg_match('/[^a-z0-9_]/i', $modulename)) {
224  $error++;
225  setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
226  }
227 
228  if (!$error) {
229  $srcdir = DOL_DOCUMENT_ROOT.'/modulebuilder/template';
230  $destdir = $dirins.'/'.strtolower($modulename);
231 
232  $arrayreplacement = array(
233  'mymodule'=>strtolower($modulename),
234  'MyModule'=>$modulename
235  );
236 
237  $result = dolCopyDir($srcdir, $destdir, 0, 0, $arrayreplacement);
238  //dol_mkdir($destfile);
239  if ($result <= 0) {
240  if ($result < 0) {
241  $error++;
242  $langs->load("errors");
243  setEventMessages($langs->trans("ErrorFailToCopyDir", $srcdir, $destdir), null, 'errors');
244  } else {
245  // $result == 0
246  setEventMessages($langs->trans("AllFilesDidAlreadyExist", $srcdir, $destdir), null, 'warnings');
247  }
248  }
249 
250  // Copy last html.formsetup.class.php' to backport folder
251  $tryToCopyFromSetupClass = true;
252  $backportDest = $destdir .'/backport/v16/core/class';
253  $backportFileSrc = DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
254  $backportFileDest = $backportDest.'/html.formsetup.class.php';
255  $result = dol_mkdir($backportDest);
256 
257  if ($result < 0) {
258  $error++;
259  $langs->load("errors");
260  setEventMessages($langs->trans("ErrorFailToCreateDir", $backportDest), null, 'errors');
261  $tryToCopyFromSetupClass = false;
262  }
263 
264  if ($tryToCopyFromSetupClass) {
265  $result = dol_copy($backportFileSrc, $backportFileDest);
266  if ($result <= 0) {
267  if ($result < 0) {
268  $error++;
269  $langs->load("errors");
270  setEventMessages($langs->trans("ErrorFailToCopyFile", $backportFileSrc, $backportFileDest), null, 'errors');
271  } else {
272  setEventMessages($langs->trans("FileDidAlreadyExist", $backportFileDest), null, 'warnings');
273  }
274  }
275  }
276 
277  if (!empty($conf->global->MODULEBUILDER_USE_ABOUT)) {
278  dol_delete_file($destdir.'/admin/about.php');
279  }
280 
281  // Delete dir and files that can be generated in sub tabs later if we need them (we want a minimal module first)
282  dol_delete_dir_recursive($destdir.'/build/doxygen');
283  dol_delete_dir_recursive($destdir.'/core/modules/mailings');
284  dol_delete_dir_recursive($destdir.'/core/modules/'.strtolower($modulename));
285  dol_delete_dir_recursive($destdir.'/core/tpl');
286  dol_delete_dir_recursive($destdir.'/core/triggers');
287  dol_delete_dir_recursive($destdir.'/doc');
288  //dol_delete_dir_recursive($destdir.'/.tx');
289  dol_delete_dir_recursive($destdir.'/core/boxes');
290 
291  dol_delete_file($destdir.'/admin/myobject_extrafields.php');
292 
293  dol_delete_file($destdir.'/sql/data.sql');
294  dol_delete_file($destdir.'/sql/update_x.x.x-y.y.y.sql');
295 
296  dol_delete_file($destdir.'/class/actions_'.strtolower($modulename).'.class.php');
297  dol_delete_file($destdir.'/class/api_'.strtolower($modulename).'.class.php');
298 
299  dol_delete_file($destdir.'/css/'.strtolower($modulename).'.css.php');
300 
301  dol_delete_file($destdir.'/js/'.strtolower($modulename).'.js.php');
302 
303  dol_delete_file($destdir.'/scripts/'.strtolower($modulename).'.php');
304 
305  dol_delete_file($destdir.'/test/phpunit/'.$modulename.'FunctionnalTest.php');
306 
307  // Delete some files related to Object (because the previous dolCopyDir has copied everything)
308  dol_delete_file($destdir.'/myobject_card.php');
309  dol_delete_file($destdir.'/myobject_contact.php');
310  dol_delete_file($destdir.'/myobject_note.php');
311  dol_delete_file($destdir.'/myobject_document.php');
312  dol_delete_file($destdir.'/myobject_agenda.php');
313  dol_delete_file($destdir.'/myobject_list.php');
314  dol_delete_file($destdir.'/lib/'.strtolower($modulename).'_myobject.lib.php');
315  dol_delete_file($destdir.'/test/phpunit/MyObjectTest.php');
316  dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.sql');
317  dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.sql');
318  dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject.key.sql');
319  dol_delete_file($destdir.'/sql/llx_'.strtolower($modulename).'_myobject_extrafields.key.sql');
320  dol_delete_file($destdir.'/class/myobject.class.php');
321 
322  dol_delete_dir($destdir.'/class', 1);
323  dol_delete_dir($destdir.'/sql', 1);
324  dol_delete_dir($destdir.'/scripts', 1);
325  dol_delete_dir($destdir.'/js', 1);
326  dol_delete_dir($destdir.'/css', 1);
327  dol_delete_dir($destdir.'/test/phpunit', 1);
328  dol_delete_dir($destdir.'/test', 1);
329  }
330 
331  // Edit PHP files
332  if (!$error) {
333  $listofphpfilestoedit = dol_dir_list($destdir, 'files', 1, '\.(php|MD|js|sql|txt|xml|lang)$', '', 'fullname', SORT_ASC, 0, 1);
334  foreach ($listofphpfilestoedit as $phpfileval) {
335  //var_dump($phpfileval['fullname']);
336  $arrayreplacement = array(
337  'mymodule'=>strtolower($modulename),
338  'MyModule'=>$modulename,
339  'MYMODULE'=>strtoupper($modulename),
340  'My module'=>$modulename,
341  'my module'=>$modulename,
342  'Mon module'=>$modulename,
343  'mon module'=>$modulename,
344  'htdocs/modulebuilder/template'=>strtolower($modulename),
345  '---Put here your own copyright and developer email---'=>dol_print_date($now, '%Y').' '.$user->getFullName($langs).($user->email ? ' <'.$user->email.'>' : ''),
346  'Editor name'=>$editorname,
347  'https://www.example.com'=>$editorurl,
348  '$this->version = \'1.0\''=>'$this->version = \''.$version.'\'',
349  '$this->picto = \'generic\';'=>(empty($picto)) ? '$this->picto = \'generic\'' : '$this->picto = \''.$picto.'\';',
350  "modulefamily" =>$family,
351  '500000'=>$idmodule
352  );
353 
354  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_EDITOR_NAME)) {
355  $arrayreplacement['Editor name'] = $conf->global->MODULEBUILDER_SPECIFIC_EDITOR_NAME;
356  }
357  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_EDITOR_URL)) {
358  $arrayreplacement['https://www.example.com'] = $conf->global->MODULEBUILDER_SPECIFIC_EDITOR_URL;
359  }
360  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_AUTHOR)) {
361  $arrayreplacement['---Put here your own copyright and developer email---'] = dol_print_date($now, '%Y').' '.$conf->global->MODULEBUILDER_SPECIFIC_AUTHOR;
362  }
363  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_VERSION)) {
364  $arrayreplacement['1.0'] = $conf->global->MODULEBUILDER_SPECIFIC_VERSION;
365  }
366  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_FAMILY)) {
367  $arrayreplacement['modulefamily'] = $conf->global->MODULEBUILDER_SPECIFIC_FAMILY;
368  }
369 
370  $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement);
371  //var_dump($result);
372  if ($result < 0) {
373  setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
374  }
375  }
376 
377  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_README)) {
378  setEventMessages($langs->trans("ContentOfREADMECustomized"), null, 'warnings');
379  dol_delete_file($destdir.'/README.md');
380  file_put_contents($destdir.'/README.md', $conf->global->MODULEBUILDER_SPECIFIC_README);
381  }
382  }
383 
384  if (!$error) {
385  setEventMessages('ModuleInitialized', null);
386  $module = $modulename;
387 
388  clearstatcache(true);
389  if (function_exists('opcache_invalidate')) {
390  opcache_reset(); // remove the include cache hell !
391  }
392 
393  header("Location: ".$_SERVER["PHP_SELF"].'?module='.$modulename);
394  exit;
395  }
396 }
397 
398 
399 // init API, PHPUnit
400 if ($dirins && in_array($action, array('initapi', 'initphpunit', 'initpagecontact', 'initpagedocument', 'initpagenote', 'initpageagenda')) && !empty($module)) {
401  $modulename = ucfirst($module); // Force first letter in uppercase
402  $objectname = $tabobj;
403  $varnametoupdate = '';
404 
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/', $objectname, $stringtoadd);
1348  $stringtoadd = preg_replace('/mymodule/', strtolower($module), $stringtoadd);
1349  $stringtoadd = preg_replace('/myobject/', strtolower($objectname), $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  if (!$error) {
1363  // Edit PHP files to make replacement
1364  foreach ($filetogenerate as $destfile) {
1365  $phpfileval['fullname'] = $destdir.'/'.$destfile;
1366 
1367  //var_dump($phpfileval['fullname']);
1368  $arrayreplacement = array(
1369  'mymodule'=>strtolower($module),
1370  'MyModule'=>$module,
1371  'MYMODULE'=>strtoupper($module),
1372  'My module'=>$module,
1373  'my module'=>$module,
1374  'mon module'=>$module,
1375  'Mon module'=>$module,
1376  'htdocs/modulebuilder/template/'=>strtolower($modulename),
1377  'myobject'=>strtolower($objectname),
1378  'MyObject'=>$objectname,
1379  //'MYOBJECT'=>strtoupper($objectname),
1380  '---Put here your own copyright and developer email---'=>dol_print_date($now, '%Y').' '.$user->getFullName($langs).($user->email ? ' <'.$user->email.'>' : '')
1381  );
1382 
1383  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_EDITOR_NAME)) {
1384  $arrayreplacement['Editor name'] = $conf->global->MODULEBUILDER_SPECIFIC_EDITOR_NAME;
1385  }
1386  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_EDITOR_URL)) {
1387  $arrayreplacement['https://www.example.com'] = $conf->global->MODULEBUILDER_SPECIFIC_EDITOR_URL;
1388  }
1389  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_AUTHOR)) {
1390  $arrayreplacement['---Put here your own copyright and developer email---'] = dol_print_date($now, '%Y').' '.$conf->global->MODULEBUILDER_SPECIFIC_AUTHOR;
1391  }
1392  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_VERSION)) {
1393  $arrayreplacement['1.0'] = $conf->global->MODULEBUILDER_SPECIFIC_VERSION;
1394  }
1395  if (!empty($conf->global->MODULEBUILDER_SPECIFIC_FAMILY)) {
1396  $arrayreplacement['other'] = $conf->global->MODULEBUILDER_SPECIFIC_FAMILY;
1397  }
1398 
1399  $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement);
1400  //var_dump($result);
1401  if ($result < 0) {
1402  setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors');
1403  }
1404  }
1405  }
1406 
1407  if (!$error) {
1408  // Edit the class file to write properties
1409  $object = rebuildObjectClass($destdir, $module, $objectname, $newmask);
1410 
1411  if (is_numeric($object) && $object <= 0) {
1412  $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1413  setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1414  $error++;
1415  }
1416  }
1417  if (!$error) {
1418  // Edit sql with new properties
1419  $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, '', $object);
1420 
1421  if ($result <= 0) {
1422  setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null);
1423  $error++;
1424  }
1425  }
1426 
1427  if (!$error) {
1428  setEventMessages($langs->trans('FilesForObjectInitialized', $objectname), null);
1429  $tabobj = $objectname;
1430  } else {
1431  $tabobj = 'newobject';
1432  }
1433 }
1434 
1435 // Add a dictionary
1436 if ($dirins && $action == 'initdic' && $module && $dicname) {
1437  if (!$error) {
1438  $newdicname = $dicname;
1439  if (!preg_match('/^c_/', $newdicname)) {
1440  $newdicname = 'c_'.$dicname;
1441  }
1442 
1443  // TODO
1444 
1445  setEventMessages($langs->trans("FeatureNotYetAvailable"), null, 'errors');
1446  }
1447 }
1448 
1449 // Delete a SQL table
1450 if ($dirins && ($action == 'droptable' || $action == 'droptableextrafields') && !empty($module) && !empty($tabobj)) {
1451  $objectname = $tabobj;
1452 
1453  $arrayoftables = array();
1454  if ($action == 'droptable') {
1455  $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj);
1456  }
1457  if ($action == 'droptableextrafields') {
1458  $arrayoftables[] = MAIN_DB_PREFIX.strtolower($module).'_'.strtolower($tabobj).'_extrafields';
1459  }
1460 
1461  foreach ($arrayoftables as $tabletodrop) {
1462  $nb = -1;
1463  $sql = "SELECT COUNT(*) as nb FROM ".$tabletodrop;
1464  $resql = $db->query($sql);
1465  if ($resql) {
1466  $obj = $db->fetch_object($resql);
1467  if ($obj) {
1468  $nb = $obj->nb;
1469  }
1470  } else {
1471  if ($db->lasterrno() == 'DB_ERROR_NOSUCHTABLE') {
1472  setEventMessages($langs->trans("TableDoesNotExists", $tabletodrop), null, 'warnings');
1473  } else {
1474  dol_print_error($db);
1475  }
1476  }
1477  if ($nb == 0) {
1478  $resql = $db->DDLDropTable($tabletodrop);
1479  //var_dump($resql);
1480  setEventMessages($langs->trans("TableDropped", $tabletodrop), null, 'mesgs');
1481  } elseif ($nb > 0) {
1482  setEventMessages($langs->trans("TableNotEmptyDropCanceled", $tabletodrop), null, 'warnings');
1483  }
1484  }
1485 }
1486 
1487 if ($dirins && $action == 'addproperty' && empty($cancel) && !empty($module) && !empty($tabobj)) {
1488  $error = 0;
1489 
1490  $objectname = $tabobj;
1491 
1492  $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1493  $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1494 
1495  $srcdir = $dirread.'/'.strtolower($module);
1496  $destdir = $dirins.'/'.strtolower($module);
1497  dol_mkdir($destdir);
1498 
1499  // We click on add property
1500  if (!GETPOST('regenerateclasssql') && !GETPOST('regeneratemissing')) {
1501  if (!GETPOST('propname', 'aZ09')) {
1502  $error++;
1503  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Name")), null, 'errors');
1504  }
1505  if (!GETPOST('proplabel', 'alpha')) {
1506  $error++;
1507  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
1508  }
1509  if (!GETPOST('proptype', 'alpha')) {
1510  $error++;
1511  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Type")), null, 'errors');
1512  }
1513 
1514  if (!$error && !GETPOST('regenerateclasssql')&& !GETPOST('regeneratemissing')) {
1515  $addfieldentry = array(
1516  'name'=>GETPOST('propname', 'aZ09'),
1517  'label'=>GETPOST('proplabel', 'alpha'),
1518  'type'=>GETPOST('proptype', 'alpha'),
1519  'arrayofkeyval'=>GETPOST('proparrayofkeyval', 'restricthtml'), // Example json string '{"0":"Draft","1":"Active","-1":"Cancel"}'
1520  'visible'=>GETPOST('propvisible', 'int'),
1521  'enabled'=>GETPOST('propenabled', 'int'),
1522  'position'=>GETPOST('propposition', 'int'),
1523  'notnull'=>GETPOST('propnotnull', 'int'),
1524  'index'=>GETPOST('propindex', 'int'),
1525  'searchall'=>GETPOST('propsearchall', 'int'),
1526  'isameasure'=>GETPOST('propisameasure', 'int'),
1527  'comment'=>GETPOST('propcomment', 'alpha'),
1528  'help'=>GETPOST('prophelp', 'alpha'),
1529  'css'=>GETPOST('propcss', 'alpha'), // Can be 'maxwidth500 widthcentpercentminusxx' for example
1530  'cssview'=>GETPOST('propcssview', 'alpha'),
1531  'csslist'=>GETPOST('propcsslist', 'alpha'),
1532  'default'=>GETPOST('propdefault', 'restricthtml'),
1533  'noteditable'=>intval(GETPOST('propnoteditable', 'int')),
1534  'alwayseditable'=>intval(GETPOST('propalwayseditable', 'int')),
1535  'validate' => GETPOST('propvalidate', 'int')
1536  );
1537 
1538 
1539  if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
1540  $addfieldentry['arrayofkeyval'] = json_decode($addfieldentry['arrayofkeyval'], true);
1541  }
1542  }
1543  } else {
1544  $addfieldentry = array();
1545  }
1546 
1547  /*if (GETPOST('regeneratemissing'))
1548  {
1549  setEventMessages($langs->trans("FeatureNotYetAvailable"), null, 'warnings');
1550  $error++;
1551  }*/
1552 
1553  $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1554 
1555  // Edit the class file to write properties
1556  if (!$error) {
1557  $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, $addfieldentry, $moduletype);
1558 
1559  if (is_numeric($object) && $object <= 0) {
1560  $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1561  setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1562  $error++;
1563  }
1564  }
1565 
1566  // Edit sql with new properties
1567  if (!$error) {
1568  $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object, $moduletype);
1569 
1570  if ($result <= 0) {
1571  setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1572  $error++;
1573  }
1574  }
1575 
1576  if (!$error) {
1577  clearstatcache(true);
1578 
1579  setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1580 
1581  setEventMessages($langs->trans('WarningDatabaseIsNotUpdated'), null);
1582 
1583  // Make a redirect to reload all data
1584  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname.'&nocache='.time());
1585 
1586  exit;
1587  }
1588 }
1589 
1590 if ($dirins && $action == 'confirm_deleteproperty' && $propertykey) {
1591  $objectname = $tabobj;
1592 
1593  $dirins = $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
1594  $moduletype = $listofmodules[strtolower($module)]['moduletype'];
1595 
1596  $srcdir = $dirread.'/'.strtolower($module);
1597  $destdir = $dirins.'/'.strtolower($module);
1598  dol_mkdir($destdir);
1599 
1600  // Edit the class file to write properties
1601  if (!$error) {
1602  $object = rebuildObjectClass($destdir, $module, $objectname, $newmask, $srcdir, array(), $propertykey);
1603 
1604  if (is_numeric($object) && $object <= 0) {
1605  $pathoffiletoeditsrc = $destdir.'/class/'.strtolower($objectname).'.class.php';
1606  setEventMessages($langs->trans('ErrorFailToCreateFile', $pathoffiletoeditsrc), null, 'errors');
1607  $error++;
1608  }
1609  }
1610 
1611  // Edit sql with new properties
1612  if (!$error) {
1613  $result = rebuildObjectSql($destdir, $module, $objectname, $newmask, $srcdir, $object);
1614 
1615  if ($result <= 0) {
1616  setEventMessages($langs->trans('ErrorFailToCreateFile', '.sql'), null, 'errors');
1617  $error++;
1618  }
1619  }
1620 
1621  if (!$error) {
1622  setEventMessages($langs->trans('FilesForObjectUpdated', $objectname), null);
1623 
1624  clearstatcache(true);
1625 
1626  // Make a redirect to reload all data
1627  header("Location: ".DOL_URL_ROOT.'/modulebuilder/index.php?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname);
1628 
1629  exit;
1630  }
1631 }
1632 
1633 if ($dirins && $action == 'confirm_deletemodule') {
1634  if (preg_match('/[^a-z0-9_]/i', $module)) {
1635  $error++;
1636  setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1637  }
1638 
1639  if (!$error) {
1640  $modulelowercase = strtolower($module);
1641 
1642  // Dir for module
1643  $dir = $dirins.'/'.$modulelowercase;
1644 
1645  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1646 
1647  // Dir for module
1648  $dir = dol_buildpath($modulelowercase, 0);
1649 
1650  // Zip file to build
1651  $FILENAMEZIP = '';
1652 
1653  // Load module
1654  dol_include_once($pathtofile);
1655  $class = 'mod'.$module;
1656 
1657  if (class_exists($class)) {
1658  try {
1659  $moduleobj = new $class($db);
1660  } catch (Exception $e) {
1661  $error++;
1662  dol_print_error($db, $e->getMessage());
1663  }
1664  } else {
1665  $error++;
1666  $langs->load("errors");
1667  dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1668  exit;
1669  }
1670 
1671  $moduleobj->remove();
1672 
1673  $result = dol_delete_dir_recursive($dir);
1674 
1675  if ($result > 0) {
1676  setEventMessages($langs->trans("DirWasRemoved", $modulelowercase), null);
1677 
1678  clearstatcache(true);
1679  if (function_exists('opcache_invalidate')) {
1680  opcache_reset(); // remove the include cache hell !
1681  }
1682 
1683  header("Location: ".$_SERVER["PHP_SELF"].'?module=deletemodule');
1684  exit;
1685  } else {
1686  setEventMessages($langs->trans("PurgeNothingToDelete"), null, 'warnings');
1687  }
1688  }
1689 
1690  $action = '';
1691  $module = 'deletemodule';
1692 }
1693 
1694 if ($dirins && $action == 'confirm_deleteobject' && $objectname) {
1695  if (preg_match('/[^a-z0-9_]/i', $objectname)) {
1696  $error++;
1697  setEventMessages($langs->trans("SpaceOrSpecialCharAreNotAllowed"), null, 'errors');
1698  }
1699 
1700  if (!$error) {
1701  $modulelowercase = strtolower($module);
1702  $objectlowercase = strtolower($objectname);
1703 
1704  // Dir for module
1705  $dir = $dirins.'/'.$modulelowercase;
1706 
1707  // Delete some files
1708  $filetodelete = array(
1709  'myobject_card.php'=>strtolower($objectname).'_card.php',
1710  'myobject_note.php'=>strtolower($objectname).'_note.php',
1711  'myobject_contact.php'=>strtolower($objectname).'_contact.php',
1712  'myobject_document.php'=>strtolower($objectname).'_document.php',
1713  'myobject_agenda.php'=>strtolower($objectname).'_agenda.php',
1714  'myobject_list.php'=>strtolower($objectname).'_list.php',
1715  'admin/myobject_extrafields.php'=>'admin/'.strtolower($objectname).'_extrafields.php',
1716  'lib/mymodule_myobject.lib.php'=>'lib/'.strtolower($module).'_'.strtolower($objectname).'.lib.php',
1717  'test/phpunit/MyObjectTest.php'=>'test/phpunit/'.strtolower($objectname).'Test.php',
1718  'sql/llx_mymodule_myobject.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql',
1719  'sql/llx_mymodule_myobject_extrafields.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.sql',
1720  'sql/llx_mymodule_myobject.key.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql',
1721  'sql/llx_mymodule_myobject_extrafields.key.sql'=>'sql/llx_'.strtolower($module).'_'.strtolower($objectname).'_extrafields.key.sql',
1722  'scripts/myobject.php'=>'scripts/'.strtolower($objectname).'.php',
1723  'class/myobject.class.php'=>'class/'.strtolower($objectname).'.class.php',
1724  'class/api_myobject.class.php'=>'class/api_'.strtolower($module).'.class.php',
1725  'core/modules/mymodule/mod_myobject_advanced.php'=>'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_advanced.php',
1726  'core/modules/mymodule/mod_myobject_standard.php'=>'core/modules/'.strtolower($module).'/mod_'.strtolower($objectname).'_standard.php',
1727  'core/modules/mymodule/modules_myobject.php'=>'core/modules/'.strtolower($module).'/modules_'.strtolower($objectname).'.php',
1728  'core/modules/mymodule/doc/doc_generic_myobject_odt.modules.php'=>'core/modules/'.strtolower($module).'/doc/doc_generic_'.strtolower($objectname).'_odt.modules.php',
1729  'core/modules/mymodule/doc/pdf_standard_myobject.modules.php'=>'core/modules/'.strtolower($module).'/doc/pdf_standard_'.strtolower($objectname).'.modules.php'
1730  );
1731 
1732  //menu for the object selected
1733  $stringtoedit = "\$this->menu[\$r++]=array(
1734  // '' 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
1735  'fk_menu'=>'fk_mainmenu=".strtolower($module)."',
1736  // This is a Left menu entry
1737  'type'=>'left',
1738  'titre'=>'List ".ucfirst($objectname)."',
1739  'mainmenu'=>'".strtolower($module)."',
1740  'leftmenu'=>'".strtolower($module)."_".strtolower($objectname)."',
1741  'url'=>'/".strtolower($module)."/".strtolower($objectname)."_list.php',
1742  // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
1743  'langs'=>'".strtolower($module)."@".strtolower($module)."',
1744  'position'=>1100+\$r,
1745  // Define condition to show or hide menu entry. Use '\$conf->".strtolower($module)."->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected.
1746  'enabled'=>'\$conf->".strtolower($module)."->enabled',
1747  // Use 'perms'=>'\$user->rights->".strtolower($module)."->level1->level2' if you want your menu with a permission rules
1748  'perms'=>'1',
1749  'target'=>'',
1750  // 0=Menu for internal users, 1=external users, 2=both
1751  'user'=>2,
1752  );
1753  \$this->menu[\$r++]=array(
1754  // '' 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
1755  'fk_menu'=>'fk_mainmenu=".strtolower($module).",fk_leftmenu=".strtolower($module)."_".strtolower($objectname)."',
1756  // This is a Left menu entry
1757  'type'=>'left',
1758  'titre'=>'New ".ucfirst($objectname)."',
1759  'mainmenu'=>'".strtolower($module)."',
1760  'leftmenu'=>'".strtolower($module)."_".strtolower($objectname)."',
1761  'url'=>'/".strtolower($module)."/".strtolower($objectname)."_card.php?action=create',
1762  // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
1763  'langs'=>'".strtolower($module)."@".strtolower($module)."',
1764  'position'=>1100+\$r,
1765  // Define condition to show or hide menu entry. Use '\$conf->".strtolower($module)."->enabled' if entry must be visible if module is enabled. Use '\$leftmenu==\'system\'' to show if leftmenu system is selected.
1766  'enabled'=>'\$conf->".strtolower($module)."->enabled',
1767  // Use 'perms'=>'\$user->rights->".strtolower($module)."->level1->level2' if you want your menu with a permission rules
1768  'perms'=>'1',
1769  'target'=>'',
1770  // 0=Menu for internal users, 1=external users, 2=both
1771  'user'=>2
1772  );";
1773 
1774  $moduledescriptorfile = $dirins.'/'.strtolower($module).'/core/modules/mod'.$module.'.class.php';
1775 
1776  $check = dolReplaceInFile($moduledescriptorfile, array($stringtoedit => ''));
1777  if ($check > 0) {
1778  dolReplaceInFile($moduledescriptorfile, array('/*'.strtoupper($objectname).'*/' => ''));
1779  }
1780 
1781  $resultko = 0;
1782  foreach ($filetodelete as $tmpfiletodelete) {
1783  $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete, 0, 0, 1);
1784  $resulttmp = dol_delete_file($dir.'/'.$tmpfiletodelete.'.back', 0, 0, 1);
1785  if (!$resulttmp) {
1786  $resultko++;
1787  }
1788  }
1789 
1790  if ($resultko == 0) {
1791  setEventMessages($langs->trans("FilesDeleted"), null);
1792  } else {
1793  setEventMessages($langs->trans("ErrorSomeFilesCouldNotBeDeleted"), null, 'warnings');
1794  }
1795  }
1796 
1797  $action = '';
1798  $tabobj = 'deleteobject';
1799 }
1800 
1801 if ($dirins && $action == 'generatedoc') {
1802  $modulelowercase = strtolower($module);
1803 
1804  // Dir for module
1805  $dirofmodule = dol_buildpath($modulelowercase, 0).'/doc';
1806 
1807  $FILENAMEDOC = strtolower($module).'.html';
1808 
1809  $util = new Utils($db);
1810  $result = $util->generateDoc($module);
1811 
1812  if ($result > 0) {
1813  setEventMessages($langs->trans("DocFileGeneratedInto", $dirofmodule), null);
1814  } else {
1815  setEventMessages($util->error, $util->errors, 'errors');
1816  }
1817 }
1818 
1819 if ($dirins && $action == 'generatepackage') {
1820  $modulelowercase = strtolower($module);
1821 
1822  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
1823 
1824  // Dir for module
1825  $dir = dol_buildpath($modulelowercase, 0);
1826 
1827  // Zip file to build
1828  $FILENAMEZIP = '';
1829 
1830  // Load module
1831  dol_include_once($pathtofile);
1832  $class = 'mod'.$module;
1833 
1834  if (class_exists($class)) {
1835  try {
1836  $moduleobj = new $class($db);
1837  } catch (Exception $e) {
1838  $error++;
1839  dol_print_error($db, $e->getMessage());
1840  }
1841  } else {
1842  $error++;
1843  $langs->load("errors");
1844  dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
1845  exit;
1846  }
1847 
1848  $arrayversion = explode('.', $moduleobj->version, 3);
1849  if (count($arrayversion)) {
1850  $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : '.'.$arrayversion[2]).'.zip';
1851 
1852  $dirofmodule = dol_buildpath($modulelowercase, 0).'/bin';
1853  $outputfilezip = $dirofmodule.'/'.$FILENAMEZIP;
1854  if ($dirofmodule) {
1855  if (!dol_is_dir($dirofmodule)) {
1856  dol_mkdir($dirofmodule);
1857  }
1858  // Note: We exclude /bin/ to not include the already generated zip
1859  $result = dol_compress_dir($dir, $outputfilezip, 'zip', '/\/bin\/|\.git|\.old|\.back|\.ssh/', $modulelowercase);
1860  } else {
1861  $result = -1;
1862  }
1863 
1864  if ($result > 0) {
1865  setEventMessages($langs->trans("ZipFileGeneratedInto", $outputfilezip), null);
1866  } else {
1867  $error++;
1868  $langs->load("errors");
1869  setEventMessages($langs->trans("ErrorFailToGenerateFile", $outputfilezip), null, 'errors');
1870  }
1871  } else {
1872  $error++;
1873  $langs->load("errors");
1874  setEventMessages($langs->trans("ErrorCheckVersionIsDefined"), null, 'errors');
1875  }
1876 }
1877 
1878 
1879 // Save file
1880 if ($action == 'savefile' && empty($cancel)) {
1881  $relofcustom = basename($dirins);
1882 
1883  if ($relofcustom) {
1884  // Check that relative path ($file) start with name 'custom'
1885  if (!preg_match('/^'.$relofcustom.'/', $file)) {
1886  $file = $relofcustom.'/'.$file;
1887  }
1888 
1889  $pathoffile = dol_buildpath($file, 0);
1890  $pathoffilebackup = dol_buildpath($file.'.back', 0);
1891 
1892  // Save old version
1893  if (dol_is_file($pathoffile)) {
1894  dol_copy($pathoffile, $pathoffilebackup, 0, 1);
1895  }
1896 
1897  $check = 'restricthtml';
1898  $srclang = dol_mimetype($pathoffile, '', 3);
1899  if ($srclang == 'md') {
1900  $check = 'restricthtml';
1901  }
1902  if ($srclang == 'lang') {
1903  $check = 'restricthtml';
1904  }
1905  if ($srclang == 'php') {
1906  $check = 'none';
1907  }
1908 
1909  $content = GETPOST('editfilecontent', $check);
1910 
1911  // Save file on disk
1912  if ($content) {
1913  dol_delete_file($pathoffile);
1914  $result = file_put_contents($pathoffile, $content);
1915  if ($result) {
1916  @chmod($pathoffile, octdec($newmask));
1917 
1918  setEventMessages($langs->trans("FileSaved"), null);
1919  } else {
1920  setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
1921  }
1922  } else {
1923  setEventMessages($langs->trans("ContentCantBeEmpty"), null, 'errors');
1924  //$action='editfile';
1925  $error++;
1926  }
1927  }
1928 }
1929 
1930 // Enable module
1931 if ($action == 'set' && $user->admin) {
1932  $param = '';
1933  if ($module) {
1934  $param .= '&module='.urlencode($module);
1935  }
1936  if ($tab) {
1937  $param .= '&tab='.urlencode($tab);
1938  }
1939  if ($tabobj) {
1940  $param .= '&tabobj='.urlencode($tabobj);
1941  }
1942 
1943  $value = GETPOST('value', 'alpha');
1944  $resarray = activateModule($value);
1945  if (!empty($resarray['errors'])) {
1946  setEventMessages('', $resarray['errors'], 'errors');
1947  } else {
1948  //var_dump($resarray);exit;
1949  if ($resarray['nbperms'] > 0) {
1950  $tmpsql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1";
1951  $resqltmp = $db->query($tmpsql);
1952  if ($resqltmp) {
1953  $obj = $db->fetch_object($resqltmp);
1954  //var_dump($obj->nb);exit;
1955  if ($obj && $obj->nb > 1) {
1956  $msg = $langs->trans('ModuleEnabledAdminMustCheckRights');
1957  setEventMessages($msg, null, 'warnings');
1958  }
1959  } else {
1960  dol_print_error($db);
1961  }
1962  }
1963  }
1964  header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
1965  exit;
1966 }
1967 
1968 // Disable module
1969 if ($action == 'reset' && $user->admin) {
1970  $param = '';
1971  if ($module) {
1972  $param .= '&module='.urlencode($module);
1973  }
1974  if ($tab) {
1975  $param .= '&tab='.urlencode($tab);
1976  }
1977  if ($tabobj) {
1978  $param .= '&tabobj='.urlencode($tabobj);
1979  }
1980 
1981  $value = GETPOST('value', 'alpha');
1982  $result = unActivateModule($value);
1983  if ($result) {
1984  setEventMessages($result, null, 'errors');
1985  }
1986  header("Location: ".$_SERVER["PHP_SELF"]."?".$param);
1987  exit;
1988 }
1989 
1990 
1991 
1992 /*
1993  * View
1994  */
1995 
1996 $form = new Form($db);
1997 $formadmin = new FormAdmin($db);
1998 
1999 // Set dir where external modules are installed
2000 if (!dol_is_dir($dirins)) {
2001  dol_mkdir($dirins);
2002 }
2003 $dirins_ok = (dol_is_dir($dirins));
2004 
2005 $help_url = '';
2006 $morejs = array(
2007  '/includes/ace/src/ace.js',
2008  '/includes/ace/src/ext-statusbar.js',
2009  '/includes/ace/src/ext-language_tools.js',
2010  //'/includes/ace/src/ext-chromevox.js'
2011 );
2012 $morecss = array();
2013 
2014 llxHeader('', $langs->trans("ModuleBuilder"), $help_url, '', 0, 0, $morejs, $morecss, '', 'classforhorizontalscrolloftabs');
2015 
2016 
2017 $text = $langs->trans("ModuleBuilder");
2018 
2019 print load_fiche_titre($text, '', 'title_setup');
2020 
2021 print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModuleBuilderDesc", 'https://wiki.dolibarr.org/index.php/Module_development#Create_your_module').'</span>';
2022 print '<br class="hideonsmartphone">';
2023 
2024 //print $textforlistofdirs;
2025 //print '<br>';
2026 //var_dump($listofmodules);
2027 
2028 
2029 $message = '';
2030 if (!$dirins) {
2031  $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
2032  $allowfromweb = -1;
2033 } else {
2034  if ($dirins_ok) {
2035  if (!is_writable(dol_osencode($dirins))) {
2036  $langs->load("errors");
2037  $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins));
2038  $allowfromweb = 0;
2039  }
2040  } else {
2041  $message = info_admin($langs->trans("NotExistsDirect", $dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
2042  $allowfromweb = 0;
2043  }
2044 }
2045 if ($message) {
2046  print $message;
2047 }
2048 
2049 //print $langs->trans("ModuleBuilderDesc3", count($listofmodules), $FILEFLAG).'<br>';
2050 $infomodulesfound = '<div style="padding: 12px 9px 12px">'.$form->textwithpicto('', $langs->trans("ModuleBuilderDesc3", count($listofmodules)).'<br><br>'.$langs->trans("ModuleBuilderDesc4", $FILEFLAG).'<br>'.$textforlistofdirs).'</div>';
2051 
2052 
2053 
2054 $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
2055 $allowonlineinstall = true;
2056 if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
2057  $allowonlineinstall = false;
2058 }
2059 if (empty($allowonlineinstall)) {
2060  if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) {
2061  // Show clean message
2062  $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'));
2063  } else {
2064  // Show technical message
2065  $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'), 0, 0, 1, 'warning');
2066  }
2067 
2068  print $message;
2069 
2070  llxFooter();
2071  exit(0);
2072 }
2073 
2074 
2075 // Load module descriptor
2076 $error = 0;
2077 $moduleobj = null;
2078 
2079 
2080 if (!empty($module) && $module != 'initmodule' && $module != 'deletemodule') {
2081  $modulelowercase = strtolower($module);
2082  $loadclasserrormessage = '';
2083 
2084  // Load module
2085  try {
2086  $fullpathdirtodescriptor = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2087 
2088  //throw(new Exception());
2089  dol_include_once($fullpathdirtodescriptor);
2090 
2091  $class = 'mod'.$module;
2092  } catch (Throwable $e) { // This is called in PHP 7 only. Never called with PHP 5.6
2093  $loadclasserrormessage = $e->getMessage()."<br>\n";
2094  $loadclasserrormessage .= 'File: '.$e->getFile()."<br>\n";
2095  $loadclasserrormessage .= 'Line: '.$e->getLine()."<br>\n";
2096  } catch (Exception $e) {
2097  $loadclasserrormessage = $e->getMessage()."<br>\n";
2098  $loadclasserrormessage .= 'File: '.$e->getFile()."<br>\n";
2099  $loadclasserrormessage .= 'Line: '.$e->getLine()."<br>\n";
2100  }
2101 
2102  if (class_exists($class)) {
2103  try {
2104  $moduleobj = new $class($db);
2105  } catch (Exception $e) {
2106  $error++;
2107  print $e->getMessage();
2108  }
2109  } else {
2110  if (empty($forceddirread)) {
2111  $error++;
2112  }
2113  $langs->load("errors");
2114  print '<!-- ErrorFailedToLoadModuleDescriptorForXXX -->';
2115  print img_warning('').' '.$langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
2116  print $loadclasserrormessage;
2117  }
2118 }
2119 
2120 print '<br>';
2121 
2122 
2123 // Tabs for all modules
2124 $head = array();
2125 $h = 0;
2126 
2127 $head[$h][0] = $_SERVER["PHP_SELF"].'?module=initmodule';
2128 $head[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewModule").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
2129 $head[$h][2] = 'initmodule';
2130 $h++;
2131 
2132 $linktoenabledisable = '';
2133 
2134 if (is_array($listofmodules) && count($listofmodules) > 0) {
2135  // Define $linktoenabledisable
2136  $modulelowercase = strtolower($module);
2137  $const_name = 'MAIN_MODULE_'.strtoupper($module);
2138 
2139  $param = '';
2140  if ($tab) {
2141  $param .= '&tab='.urlencode($tab);
2142  }
2143  if ($module) {
2144  $param .= '&module='.urlencode($module);
2145  }
2146  if ($tabobj) {
2147  $param .= '&tabobj='.urlencode($tabobj);
2148  }
2149 
2150  $urltomodulesetup = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?search_keyword='.urlencode($module).'">'.$langs->trans('Home').'-'.$langs->trans("Setup").'-'.$langs->trans("Modules").'</a>';
2151 
2152  // Define $linktoenabledisable to show after module title
2153  if (isModEnabled($modulelowercase)) { // If module is already activated
2154  $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=reset&token='.newToken().'&value=mod'.$module.$param.'">';
2155  $linktoenabledisable .= img_picto($langs->trans("Activated"), 'switch_on', '', false, 0, 0, '', '', 1);
2156  $linktoenabledisable .= '</a>';
2157 
2158  $linktoenabledisable .= $form->textwithpicto('', $langs->trans("Warning").' : '.$langs->trans("ModuleIsLive"), -1, 'warning');
2159 
2160  $objMod = $moduleobj;
2161  $backtourlparam = '';
2162  $backtourlparam .= ($backtourlparam ? '&' : '?').'module='.$module; // No urlencode here, done later
2163  if ($tab) {
2164  $backtourlparam .= ($backtourlparam ? '&' : '?').'tab='.$tab; // No urlencode here, done later
2165  }
2166  $backtourl = $_SERVER["PHP_SELF"].$backtourlparam;
2167 
2168  $regs = array();
2169  if (is_array($objMod->config_page_url)) {
2170  $i = 0;
2171  foreach ($objMod->config_page_url as $page) {
2172  $urlpage = $page;
2173  if ($i++) {
2174  $linktoenabledisable .= ' <a href="'.$urlpage.'" title="'.$langs->trans($page).'">'.img_picto(ucfirst($page), "setup").'</a>';
2175  // print '<a href="'.$page.'">'.ucfirst($page).'</a>&nbsp;';
2176  } else {
2177  if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) {
2178  $urltouse = dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1);
2179  $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>';
2180  } else {
2181  // Case standard admin page (not a page provided by the
2182  // module but a page provided by dolibarr)
2183  $urltouse = DOL_URL_ROOT.'/admin/'.$urlpage;
2184  $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>';
2185  }
2186  }
2187  }
2188  } elseif (preg_match('/^([^@]+)@([^@]+)$/i', $objMod->config_page_url, $regs)) {
2189  $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>';
2190  }
2191  } else {
2192  if (!empty($moduleobj)) {
2193  $linktoenabledisable .= '<a class="reposition asetresetmodule valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$moduleobj->numero.'&action=set&token='.newToken().'&value=mod'.$module.$param.'">';
2194  $linktoenabledisable .= img_picto($langs->trans("ModuleIsNotActive", $urltomodulesetup), 'switch_off', 'style="padding-right: 8px"', false, 0, 0, '', 'classfortooltip', 1);
2195  $linktoenabledisable .= "</a>\n";
2196  }
2197  }
2198 
2199  // Loop to show tab of each module
2200  foreach ($listofmodules as $tmpmodule => $tmpmodulearray) {
2201  $head[$h][0] = $_SERVER["PHP_SELF"].'?module='.$tmpmodulearray['modulenamewithcase'].($forceddirread ? '@'.$dirread : '');
2202  $head[$h][1] = $tmpmodulearray['modulenamewithcase'];
2203  $head[$h][2] = $tmpmodulearray['modulenamewithcase'];
2204 
2205  if ($tmpmodulearray['modulenamewithcase'] == $module) {
2206  $head[$h][4] = '<span class="inline-block">'.$linktoenabledisable.'</span>';
2207  }
2208 
2209  $h++;
2210  }
2211 }
2212 
2213 $head[$h][0] = $_SERVER["PHP_SELF"].'?module=deletemodule';
2214 $head[$h][1] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
2215 $head[$h][2] = 'deletemodule';
2216 $h++;
2217 
2218 
2219 print dol_get_fiche_head($head, $module, '', -1, '', 0, $infomodulesfound, '', 8); // Modules
2220 
2221 if ($module == 'initmodule') {
2222  // New module
2223  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2224  print '<input type="hidden" name="token" value="'.newToken().'">';
2225  print '<input type="hidden" name="action" value="initmodule">';
2226  print '<input type="hidden" name="module" value="initmodule">';
2227 
2228  //print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc2", 'conf/conf.php', $newdircustom).'</span><br>';
2229  print '<br>';
2230 
2231  print '<div class="tagtable">';
2232 
2233  print '<div class="tagtr"><div class="tagtd">';
2234  print '<span class="opacitymedium">'.$langs->trans("IdModule").'</span>';
2235  print '</div><div class="tagtd">';
2236  print '<input type="text" name="idmodule" class="width75" value="500000" placeholder="'.dol_escape_htmltag($langs->trans("IdModule")).'">';
2237  print '<span class="opacitymedium">';
2238  print ' &nbsp; (';
2239  print dolButtonToOpenUrlInDialogPopup('popup_modules_id', $langs->transnoentitiesnoconv("SeeIDsInUse"), $langs->transnoentitiesnoconv("SeeIDsInUse"), '/admin/system/modules.php?mainmenu=home&leftmenu=admintools_info', '', '');
2240  print ' - ';
2241  print '<a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>';
2242  print ')';
2243  print '</span>';
2244  print '</div></div>';
2245 
2246  print '<div class="tagtr"><div class="tagtd">';
2247  print '<span class="opacitymedium">'.$langs->trans("ModuleName").'</span>';
2248  print '</div><div class="tagtd">';
2249  print '<input type="text" name="modulename" value="'.dol_escape_htmltag($modulename).'" autofocus>';
2250  print ' '.$form->textwithpicto('', $langs->trans("EnterNameOfModuleDesc"));
2251  print '</div></div>';
2252 
2253  print '<div class="tagtr"><div class="tagtd">';
2254  print '<span class="opacitymedium">'.$langs->trans("Description").'</span>';
2255  print '</div><div class="tagtd">';
2256  print '<input type="text" name="description" value="" class="minwidth500"><br>';
2257  print '</div></div>';
2258 
2259  print '<div class="tagtr"><div class="tagtd">';
2260  print '<span class="opacitymedium">'.$langs->trans("Version").'</span>';
2261  print '</div><div class="tagtd">';
2262  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")).'">';
2263  print '</div></div>';
2264 
2265  print '<div class="tagtr"><div class="tagtd">';
2266  print '<span class="opacitymedium">'.$langs->trans("Family").'</span>';
2267  print '</div><div class="tagtd">';
2268  print '<select name="family" id="family" class="minwidth400">';
2269  $arrayoffamilies = array(
2270  'hr' => "ModuleFamilyHr",
2271  'crm' => "ModuleFamilyCrm",
2272  'srm' => "ModuleFamilySrm",
2273  'financial' => 'ModuleFamilyFinancial',
2274  'products' => 'ModuleFamilyProducts',
2275  'projects' => 'ModuleFamilyProjects',
2276  'ecm' => 'ModuleFamilyECM',
2277  'technic' => 'ModuleFamilyTechnic',
2278  'portal' => 'ModuleFamilyPortal',
2279  'interface' => 'ModuleFamilyInterface',
2280  'base' => 'ModuleFamilyBase',
2281  'other' => 'ModuleFamilyOther'
2282  );
2283  foreach ($arrayoffamilies as $key => $value) {
2284  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>';
2285  }
2286  print '</select>';
2287  print ajax_combobox("family");
2288  print '</div></div>';
2289 
2290  print '<div class="tagtr"><div class="tagtd">';
2291  print '<span class="opacitymedium">'.$langs->trans("Picto").'</span>';
2292  print '</div><div class="tagtd">';
2293  print '<input type="text" name="idpicto" value="'.(GETPOSTISSET('idpicto') ? GETPOST('idpicto') : getDolGlobalString('MODULEBUILDER_DEFAULTPICTO', 'fa-generic')).'" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
2294  print $form->textwithpicto('', $langs->trans("Example").': fa-generic, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
2295  print '</div></div>';
2296 
2297  print '<div class="tagtr"><div class="tagtd">';
2298  print '<span class="opacitymedium">'.$langs->trans("EditorName").'</span>';
2299  print '</div><div class="tagtd">';
2300  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>';
2301  print '</div></div>';
2302 
2303  print '<div class="tagtr"><div class="tagtd">';
2304  print '<span class="opacitymedium">'.$langs->trans("EditorUrl").'</span>';
2305  print '</div><div class="tagtd">';
2306  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>';
2307  print '</div></div>';
2308 
2309  print '<br><input type="submit" class="button" name="create" value="'.dol_escape_htmltag($langs->trans("Create")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
2310  print '</form>';
2311 } elseif ($module == 'deletemodule') {
2312  print '<!-- Form to init a module -->'."\n";
2313  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="delete">';
2314  print '<input type="hidden" name="token" value="'.newToken().'">';
2315  print '<input type="hidden" name="action" value="confirm_deletemodule">';
2316  print '<input type="hidden" name="module" value="deletemodule">';
2317 
2318  print $langs->trans("EnterNameOfModuleToDeleteDesc").'<br><br>';
2319 
2320  print '<input type="text" name="module" placeholder="'.dol_escape_htmltag($langs->trans("ModuleKey")).'" value="">';
2321  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Delete").'"'.($dirins ? '' : ' disabled="disabled"').'>';
2322  print '</form>';
2323 } elseif (!empty($module)) {
2324  // Tabs for module
2325  if (!$error) {
2326  $dirread = $listofmodules[strtolower($module)]['moduledescriptorrootpath'];
2327 
2328  $head2 = array();
2329  $h = 0;
2330 
2331  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=description&module='.$module.($forceddirread ? '@'.$dirread : '');
2332  $head2[$h][1] = $langs->trans("Description");
2333  $head2[$h][2] = 'description';
2334  $h++;
2335 
2336  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '');
2337  $head2[$h][1] = $langs->trans("Objects");
2338  $head2[$h][2] = 'objects';
2339  $h++;
2340 
2341  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=languages&module='.$module.($forceddirread ? '@'.$dirread : '');
2342  $head2[$h][1] = $langs->trans("Languages");
2343  $head2[$h][2] = 'languages';
2344  $h++;
2345 
2346  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '');
2347  $head2[$h][1] = $langs->trans("Dictionaries");
2348  $head2[$h][2] = 'dictionaries';
2349  $h++;
2350 
2351  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=permissions&module='.$module.($forceddirread ? '@'.$dirread : '');
2352  $head2[$h][1] = $langs->trans("Permissions");
2353  $head2[$h][2] = 'permissions';
2354  $h++;
2355 
2356  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=tabs&module='.$module.($forceddirread ? '@'.$dirread : '');
2357  $head2[$h][1] = $langs->trans("Tabs");
2358  $head2[$h][2] = 'tabs';
2359  $h++;
2360 
2361  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=menus&module='.$module.($forceddirread ? '@'.$dirread : '');
2362  $head2[$h][1] = $langs->trans("Menus");
2363  $head2[$h][2] = 'menus';
2364  $h++;
2365 
2366  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=hooks&module='.$module.($forceddirread ? '@'.$dirread : '');
2367  $head2[$h][1] = $langs->trans("Hooks");
2368  $head2[$h][2] = 'hooks';
2369  $h++;
2370 
2371  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=triggers&module='.$module.($forceddirread ? '@'.$dirread : '');
2372  $head2[$h][1] = $langs->trans("Triggers");
2373  $head2[$h][2] = 'triggers';
2374  $h++;
2375 
2376  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=widgets&module='.$module.($forceddirread ? '@'.$dirread : '');
2377  $head2[$h][1] = $langs->trans("Widgets");
2378  $head2[$h][2] = 'widgets';
2379  $h++;
2380 
2381  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=exportimport&module='.$module.($forceddirread ? '@'.$dirread : '');
2382  $head2[$h][1] = $langs->trans("Export").'-'.$langs->trans("Import");
2383  $head2[$h][2] = 'exportimport';
2384  $h++;
2385 
2386  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=css&module='.$module.($forceddirread ? '@'.$dirread : '');
2387  $head2[$h][1] = $langs->trans("CSS");
2388  $head2[$h][2] = 'css';
2389  $h++;
2390 
2391  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=js&module='.$module.($forceddirread ? '@'.$dirread : '');
2392  $head2[$h][1] = $langs->trans("JS");
2393  $head2[$h][2] = 'js';
2394  $h++;
2395 
2396  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cli&module='.$module.($forceddirread ? '@'.$dirread : '');
2397  $head2[$h][1] = $langs->trans("CLI");
2398  $head2[$h][2] = 'cli';
2399  $h++;
2400 
2401  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=cron&module='.$module.($forceddirread ? '@'.$dirread : '');
2402  $head2[$h][1] = $langs->trans("CronList");
2403  $head2[$h][2] = 'cron';
2404  $h++;
2405 
2406  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=specifications&module='.$module.($forceddirread ? '@'.$dirread : '');
2407  $head2[$h][1] = $langs->trans("Documentation");
2408  $head2[$h][2] = 'specifications';
2409  $h++;
2410 
2411  $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=buildpackage&module='.$module.($forceddirread ? '@'.$dirread : '');
2412  $head2[$h][1] = $langs->trans("BuildPackage");
2413  $head2[$h][2] = 'buildpackage';
2414  $h++;
2415 
2416  $MAXTABFOROBJECT = 15;
2417 
2418  print '<!-- Section for a given module -->';
2419 
2420  // Note module is inside $dirread
2421 
2422  if ($tab == 'description') {
2423  print '<!-- tab=description -->'."\n";
2424  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2425  $pathtofilereadme = $modulelowercase.'/README.md';
2426  $pathtochangelog = $modulelowercase.'/ChangeLog.md';
2427 
2428  if ($action != 'editfile' || empty($file)) {
2429  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', $MAXTABFOROBJECT, 'formodulesuffix'); // Description - level 2
2430 
2431  print '<span class="opacitymedium">'.$langs->trans("ModuleBuilderDesc".$tab).'</span>';
2432  $infoonmodulepath = '';
2433  if (realpath($dirread.'/'.$modulelowercase) != $dirread.'/'.$modulelowercase) {
2434  $infoonmodulepath = '<span class="opacitymedium">'.$langs->trans("RealPathOfModule").' :</span> <strong class="wordbreak">'.realpath($dirread.'/'.$modulelowercase).'</strong><br>';
2435  print ' '.$infoonmodulepath;
2436  }
2437  print '<br>';
2438 
2439  print '<table>';
2440 
2441  print '<tr><td>';
2442  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
2443  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>';
2444  print '</td></tr>';
2445 
2446  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ReadmeFile").' : <strong class="wordbreak">'.$pathtofilereadme.'</strong>';
2447  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>';
2448  print '</td></tr>';
2449 
2450  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("ChangeLog").' : <strong class="wordbreak">'.$pathtochangelog.'</strong>';
2451  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>';
2452  print '</td></tr>';
2453 
2454  print '</table>';
2455  print '<br>';
2456 
2457  print load_fiche_titre($form->textwithpicto($langs->trans("DescriptorFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofile), '', '');
2458 
2459  if (!empty($moduleobj)) {
2460  print '<div class="underbanner clearboth"></div>';
2461  print '<div class="fichecenter">';
2462 
2463  print '<table class="border centpercent">';
2464  print '<tr class="liste_titre"><td class="titlefield">';
2465  print $langs->trans("Parameter");
2466  print '</td><td>';
2467  print $langs->trans("Value");
2468  print '</td></tr>';
2469 
2470  print '<tr><td>';
2471  print $langs->trans("IdModule");
2472  print '</td><td>';
2473  print $moduleobj->numero;
2474  print '<span class="opacitymedium">';
2475  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>';
2476  print ' - <a href="https://wiki.dolibarr.org/index.php/List_of_modules_id" target="_blank" rel="noopener noreferrer external">'.$langs->trans("SeeReservedIDsRangeHere").'</a>)';
2477  print '</span>';
2478  print '</td></tr>';
2479 
2480  print '<tr><td>';
2481  print $langs->trans("ModuleName");
2482  print '</td><td>';
2483  print $moduleobj->getName();
2484  print '</td></tr>';
2485 
2486  print '<tr><td>';
2487  print $langs->trans("Description");
2488  print '</td><td>';
2489  print $moduleobj->getDesc();
2490  print '</td></tr>';
2491 
2492  print '<tr><td>';
2493  print $langs->trans("Version");
2494  print '</td><td>';
2495  print $moduleobj->getVersion();
2496  print '</td></tr>';
2497 
2498  print '<tr><td>';
2499  print $langs->trans("Family");
2500  //print "<br>'crm','financial','hr','projects','products','ecm','technic','interface','other'";
2501  print '</td><td>';
2502  print $moduleobj->family;
2503  print '</td></tr>';
2504 
2505  print '<tr><td>';
2506  print $langs->trans("Picto");
2507  print '</td><td>';
2508  print $moduleobj->picto;
2509  print ' &nbsp; '.img_picto('', $moduleobj->picto, 'class="valignmiddle pictomodule paddingrightonly"');
2510  print '</td></tr>';
2511 
2512  print '<tr><td>';
2513  print $langs->trans("EditorName");
2514  print '</td><td>';
2515  print $moduleobj->editor_name;
2516  print '</td></tr>';
2517 
2518  print '<tr><td>';
2519  print $langs->trans("EditorUrl");
2520  print '</td><td>';
2521  if (!empty($moduleobj->editor_url)) {
2522  print '<a href="'.$moduleobj->editor_url.'" target="_blank" rel="noopener">'.$moduleobj->editor_url.' '.img_picto('', 'globe').'</a>';
2523  }
2524  print '</td></tr>';
2525 
2526  print '</table>';
2527  } else {
2528  print $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module).'<br>';
2529  }
2530 
2531  if (!empty($moduleobj)) {
2532  print '<br><br>';
2533 
2534  // Readme file
2535  print load_fiche_titre($form->textwithpicto($langs->trans("ReadmeFile"), $langs->transnoentitiesnoconv("File").' '.$pathtofilereadme), '', '');
2536 
2537  print '<!-- readme file -->';
2538  if (dol_is_file($dirread.'/'.$pathtofilereadme)) {
2539  print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getDescLong().'</div>';
2540  } else {
2541  print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtofilereadme).'</span>';
2542  }
2543 
2544  print '<br><br>';
2545 
2546  // ChangeLog
2547  print load_fiche_titre($form->textwithpicto($langs->trans("ChangeLog"), $langs->transnoentitiesnoconv("File").' '.$pathtochangelog), '', '');
2548 
2549  print '<!-- changelog file -->';
2550  if (dol_is_file($dirread.'/'.$pathtochangelog)) {
2551  print '<div class="underbanner clearboth"></div><div class="fichecenter">'.$moduleobj->getChangeLog().'</div>';
2552  } else {
2553  print '<span class="opacitymedium">'.$langs->trans("ErrorFileNotFound", $pathtochangelog).'</span>';
2554  }
2555  }
2556 
2557  print dol_get_fiche_end();
2558  } else { // Edit text file
2559  $fullpathoffile = dol_buildpath($file, 0, 1); // Description - level 2
2560 
2561  if ($fullpathoffile) {
2562  $content = file_get_contents($fullpathoffile);
2563  }
2564 
2565  // New module
2566  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2567  print '<input type="hidden" name="token" value="'.newToken().'">';
2568  print '<input type="hidden" name="action" value="savefile">';
2569  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
2570  print '<input type="hidden" name="tab" value="'.$tab.'">';
2571  print '<input type="hidden" name="module" value="'.$module.'">';
2572 
2573  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', 0, 'formodulesuffix');
2574 
2575  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%', '');
2576  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
2577 
2578  print dol_get_fiche_end();
2579 
2580  print '<center>';
2581  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
2582  print ' &nbsp; ';
2583  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
2584  print '</center>';
2585 
2586  print '</form>';
2587  }
2588  } else {
2589  print dol_get_fiche_head($head2, $tab, '', -1, '', 0, '', '', $MAXTABFOROBJECT, 'formodulesuffix'); // Level 2
2590  }
2591 
2592  if ($tab == 'languages') {
2593  print '<!-- tab=languages -->'."\n";
2594  if ($action != 'editfile' || empty($file)) {
2595  print '<span class="opacitymedium">'.$langs->trans("LanguageDefDesc").'</span><br>';
2596  print '<br>';
2597 
2598 
2599  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2600  print '<input type="hidden" name="token" value="'.newToken().'">';
2601  print '<input type="hidden" name="action" value="addlanguage">';
2602  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
2603  print '<input type="hidden" name="tab" value="'.$tab.'">';
2604  print '<input type="hidden" name="module" value="'.$module.'">';
2605  print $formadmin->select_language($conf->global->MAIN_LANG_DEFAULT, 'newlangcode', 0, 0, 1, 0, 0, 'minwidth300', 1);
2606  print '<input type="submit" name="addlanguage" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("AddLanguageFile")).'"><br>';
2607  print '</form>';
2608 
2609  print '<br>';
2610  print '<br>';
2611 
2612  $modulelowercase = strtolower($module);
2613 
2614  // Dir for module
2615  $diroflang = dol_buildpath($modulelowercase, 0);
2616  $diroflang .= '/langs';
2617  $langfiles = dol_dir_list($diroflang, 'files', 1, '\.lang$');
2618 
2619  if (!preg_match('/custom/', $dirread)) {
2620  // If this is not a module into custom
2621  $diroflang = $dirread;
2622  $diroflang .= '/langs';
2623  $langfiles = dol_dir_list($diroflang, 'files', 1, $modulelowercase.'\.lang$');
2624  }
2625 
2626  print '<table class="none">';
2627  foreach ($langfiles as $langfile) {
2628  $pathtofile = $modulelowercase.'/langs/'.$langfile['relativename'];
2629  if (!preg_match('/custom/', $dirread)) { // If this is not a module into custom
2630  $pathtofile = 'langs/'.$langfile['relativename'];
2631  }
2632  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("LanguageFile").' '.basename(dirname($pathtofile)).' : <strong class="wordbreak">'.$pathtofile.'</strong>';
2633  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>';
2634  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>';
2635  print '</td>';
2636  }
2637  print '</table>';
2638  } else {
2639  // Edit text language file
2640 
2641  //print $langs->trans("UseAsciiDocFormat").'<br>';
2642 
2643  $fullpathoffile = dol_buildpath($file, 0);
2644 
2645  $content = file_get_contents($fullpathoffile);
2646 
2647  // New module
2648  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2649  print '<input type="hidden" name="token" value="'.newToken().'">';
2650  print '<input type="hidden" name="action" value="savefile">';
2651  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
2652  print '<input type="hidden" name="tab" value="'.$tab.'">';
2653  print '<input type="hidden" name="module" value="'.$module.'">';
2654 
2655  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
2656  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'text'));
2657  print '<br>';
2658  print '<center>';
2659  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
2660  print ' &nbsp; ';
2661  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
2662  print '</center>';
2663 
2664  print '</form>';
2665  }
2666  }
2667 
2668  if ($tab == 'objects') {
2669  print '<!-- tab=objects -->'."\n";
2670  $head3 = array();
2671  $h = 0;
2672 
2673  // Dir for module
2674  $dir = $dirread.'/'.$modulelowercase.'/class';
2675 
2676  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=newobject';
2677  $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewObjectInModulebuilder").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
2678  $head3[$h][2] = 'newobject';
2679  $h++;
2680 
2681  // Scan for object class files
2682  $listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
2683 
2684  $firstobjectname = '';
2685  foreach ($listofobject as $fileobj) {
2686  if (preg_match('/^api_/', $fileobj['name'])) {
2687  continue;
2688  }
2689  if (preg_match('/^actions_/', $fileobj['name'])) {
2690  continue;
2691  }
2692 
2693  $tmpcontent = file_get_contents($fileobj['fullname']);
2694  if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
2695  //$objectname = preg_replace('/\.txt$/', '', $fileobj['name']);
2696  $objectname = $reg[1];
2697  if (empty($firstobjectname)) {
2698  $firstobjectname = $objectname;
2699  }
2700 
2701  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj='.$objectname;
2702  $head3[$h][1] = $objectname;
2703  $head3[$h][2] = $objectname;
2704  $h++;
2705  }
2706  }
2707 
2708  if ($h > 1) {
2709  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=objects&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabobj=deleteobject';
2710  $head3[$h][1] =img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("DangerZone");
2711  $head3[$h][2] = 'deleteobject';
2712  $h++;
2713  }
2714 
2715  // 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.
2716  if ($tabobj == 'newobjectifnoobj') {
2717  if ($firstobjectname) {
2718  $tabobj = $firstobjectname;
2719  } else {
2720  $tabobj = 'newobject';
2721  }
2722  }
2723 
2724  print dol_get_fiche_head($head3, $tabobj, '', -1, ''); // Level 3
2725 
2726  if ($tabobj == 'newobject') {
2727  // New object tab
2728  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2729  print '<input type="hidden" name="token" value="'.newToken().'">';
2730  print '<input type="hidden" name="action" value="initobject">';
2731  print '<input type="hidden" name="tab" value="objects">';
2732  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
2733 
2734  print '<span class="opacitymedium">'.$langs->trans("EnterNameOfObjectDesc").'</span><br><br>';
2735 
2736  print '<div class="tagtable">';
2737 
2738  print '<div class="tagtr"><div class="tagtd">';
2739  print '<span class="opacitymedium">'.$langs->trans("ObjectKey").'</span> &nbsp; ';
2740  print '</div><div class="tagtd">';
2741  print '<input type="text" name="objectname" maxlength="64" value="'.dol_escape_htmltag(GETPOST('objectname', 'alpha') ? GETPOST('objectname', 'alpha') : $modulename).'" autofocus><br>';
2742  print '</div></div>';
2743 
2744  print '<div class="tagtr"><div class="tagtd">';
2745  print '<span class="opacitymedium">'.$langs->trans("Picto").'</span> &nbsp; ';
2746  print '</div><div class="tagtd">';
2747  print '<input type="text" name="idpicto" value="fa-generic" placeholder="'.dol_escape_htmltag($langs->trans("Picto")).'">';
2748  print $form->textwithpicto('', $langs->trans("Example").': fa-generic, fa-globe, ... any font awesome code.<br>Advanced syntax is fa-fakey[_faprefix[_facolor[_fasize]]]');
2749  print '</div></div>';
2750 
2751  print '<div class="tagtr"><div class="tagtd">';
2752  print '<span class="opacitymedium">'.$langs->trans("DefinePropertiesFromExistingTable").'</span> &nbsp; ';
2753  print '</div><div class="tagtd">';
2754  print '<input type="text" name="initfromtablename" value="'.GETPOST('initfromtablename').'" placeholder="'.$langs->trans("TableName").'">';
2755  print $form->textwithpicto('', $langs->trans("DefinePropertiesFromExistingTableDesc").'<br>'.$langs->trans("DefinePropertiesFromExistingTableDesc2"));
2756  print '</div></div>';
2757 
2758  print '</div>';
2759 
2760  print '<br>';
2761  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>';
2762  print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
2763  print '<br>';
2764  print '<input type="submit" class="button small" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
2765  print '<br>';
2766  print '<br>';
2767  /*
2768  print '<br>';
2769  print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
2770  print '<br>';
2771  print '<br>';
2772  //print '<input type="checkbox" name="initfromtablecheck"> ';
2773  print $langs->trans("InitStructureFromExistingTable");
2774  print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
2775  print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
2776  print '<br>';
2777  */
2778 
2779  print '</form>';
2780  } elseif ($tabobj == 'deleteobject') {
2781  // Delete object tab
2782  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
2783  print '<input type="hidden" name="token" value="'.newToken().'">';
2784  print '<input type="hidden" name="action" value="confirm_deleteobject">';
2785  print '<input type="hidden" name="tab" value="objects">';
2786  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
2787 
2788  print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
2789 
2790  print '<input type="text" name="objectname" value="'.dol_escape_htmltag($modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'">';
2791  print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
2792  print '</form>';
2793  } else {
2794  // tabobj = module
2795  if ($action == 'deleteproperty') {
2796  $formconfirm = $form->formconfirm(
2797  $_SERVER["PHP_SELF"].'?propertykey='.urlencode(GETPOST('propertykey', 'alpha')).'&objectname='.urlencode($objectname).'&tab='.urlencode($tab).'&module='.urlencode($module).'&tabobj='.urlencode($tabobj),
2798  $langs->trans('Delete'),
2799  $langs->trans('ConfirmDeleteProperty', GETPOST('propertykey', 'alpha')),
2800  'confirm_deleteproperty',
2801  '',
2802  0,
2803  1
2804  );
2805 
2806  // Print form confirm
2807  print $formconfirm;
2808  }
2809 
2810  if ($action != 'editfile' || empty($file)) {
2811  try {
2812  //$pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
2813 
2814  $pathtoclass = strtolower($module).'/class/'.strtolower($tabobj).'.class.php';
2815  $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'.class.php';
2816  $pathtoagenda = strtolower($module).'/'.strtolower($tabobj).'_agenda.php';
2817  $pathtocard = strtolower($module).'/'.strtolower($tabobj).'_card.php';
2818  $pathtodocument = strtolower($module).'/'.strtolower($tabobj).'_document.php';
2819  $pathtolist = strtolower($module).'/'.strtolower($tabobj).'_list.php';
2820  $pathtonote = strtolower($module).'/'.strtolower($tabobj).'_note.php';
2821  $pathtocontact = strtolower($module).'/'.strtolower($tabobj).'_contact.php';
2822  $pathtophpunit = strtolower($module).'/test/phpunit/'.strtolower($tabobj).'Test.php';
2823 
2824  // Try to load object class file
2825  clearstatcache(true);
2826  if (function_exists('opcache_invalidate')) {
2827  opcache_invalidate($dirread.'/'.$pathtoclass, true); // remove the include cache hell !
2828  }
2829 
2830  if (empty($forceddirread) && empty($dirread)) {
2831  $result = dol_include_once($pathtoclass);
2832  $stringofinclude = "dol_include_once(".$pathtoclass.")";
2833  } else {
2834  $result = @include_once $dirread.'/'.$pathtoclass;
2835  $stringofinclude = "@include_once ".$dirread.'/'.$pathtoclass;
2836  }
2837  if (class_exists($tabobj)) {
2838  try {
2839  $tmpobject = @new $tabobj($db);
2840  } catch (Exception $e) {
2841  dol_syslog('Failed to load Constructor of class: '.$e->getMessage(), LOG_WARNING);
2842  }
2843  } else {
2844  print '<span class="warning">'.$langs->trans('Failed to find the class '.$tabobj.' despite the '.$stringofinclude).'</span><br><br>';
2845  }
2846 
2847  // Define path for sql file
2848  $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
2849  $result = dol_buildpath($pathtosql);
2850  if (! dol_is_file($result)) {
2851  $pathtosql = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'.sql';
2852  $result = dol_buildpath($pathtosql);
2853  if (! dol_is_file($result)) {
2854  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'-'.strtolower($module).'.sql';
2855  $result = dol_buildpath($pathtosql);
2856  if (! dol_is_file($result)) {
2857  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
2858  $result = dol_buildpath($pathtosql);
2859  if (! dol_is_file($result)) {
2860  $pathtosql = 'install/mysql/tables/llx_'.strtolower($module).'.sql';
2861  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields.sql';
2862  $result = dol_buildpath($pathtosql);
2863  } else {
2864  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_extrafields-'.strtolower($module).'.sql';
2865  }
2866  } else {
2867  $pathtosqlextra = 'install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
2868  }
2869  } else {
2870  $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields.sql';
2871  }
2872  } else {
2873  $pathtosqlextra = strtolower($module).'/sql/llx_'.strtolower($module).'_'.strtolower($tabobj).'_extrafields-'.strtolower($module).'.sql';
2874  }
2875  $pathtosqlroot = preg_replace('/\/llx_.*$/', '', $pathtosql);
2876 
2877  $pathtosqlkey = preg_replace('/\.sql$/', '.key.sql', $pathtosql);
2878  $pathtosqlextrakey = preg_replace('/\.sql$/', '.key.sql', $pathtosqlextra);
2879 
2880  $pathtolib = strtolower($module).'/lib/'.strtolower($module).'.lib.php';
2881  $pathtoobjlib = strtolower($module).'/lib/'.strtolower($module).'_'.strtolower($tabobj).'.lib.php';
2882  $pathtopicto = strtolower($module).'/img/object_'.strtolower($tabobj).'.png';
2883 
2884  //var_dump($pathtoclass);
2885  //var_dump($dirread);
2886  $realpathtoclass = $dirread.'/'.$pathtoclass;
2887  $realpathtoapi = $dirread.'/'.$pathtoapi;
2888  $realpathtoagenda = $dirread.'/'.$pathtoagenda;
2889  $realpathtocard = $dirread.'/'.$pathtocard;
2890  $realpathtodocument = $dirread.'/'.$pathtodocument;
2891  $realpathtolist = $dirread.'/'.$pathtolist;
2892  $realpathtonote = $dirread.'/'.$pathtonote;
2893  $realpathtocontact = $dirread.'/'.$pathtocontact;
2894  $realpathtophpunit = $dirread.'/'.$pathtophpunit;
2895  $realpathtosql = $dirread.'/'.$pathtosql;
2896  $realpathtosqlextra = $dirread.'/'.$pathtosqlextra;
2897  $realpathtosqlkey = $dirread.'/'.$pathtosqlkey;
2898  $realpathtosqlextrakey = $dirread.'/'.$pathtosqlextrakey;
2899  $realpathtolib = $dirread.'/'.$pathtolib;
2900  $realpathtoobjlib = $dirread.'/'.$pathtoobjlib;
2901  $realpathtopicto = $dirread.'/'.$pathtopicto;
2902 
2903  if (empty($realpathtoapi)) { // For compatibility with some old modules
2904  $pathtoapi = strtolower($module).'/class/api_'.strtolower($module).'s.class.php';
2905  $realpathtoapi = $dirread.'/'.$pathtoapi;
2906  }
2907 
2908  $urloflist = dol_buildpath('/'.$pathtolist, 1);
2909  $urlofcard = dol_buildpath('/'.$pathtocard, 1);
2910 
2911 
2912  print '<!-- section for object -->';
2913  print '<div class="fichehalfleft smallxxx">';
2914  // Main DAO class file
2915  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>';
2916  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>';
2917  print '<br>';
2918  // Image
2919  if (dol_is_file($realpathtopicto)) {
2920  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>';
2921  //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>';
2922  print '<br>';
2923  } elseif (!empty($tmpobject)) {
2924  print '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : '.img_picto('', $tmpobject->picto, 'class="pictofixedwidth"');
2925  print '<br>';
2926  }
2927 
2928  // API file
2929  print '<br>';
2930  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>';
2931  if (dol_is_file($realpathtoapi)) {
2932  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>';
2933  print ' ';
2934  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>';
2935  print ' &nbsp; ';
2936  if (empty($conf->global->$const_name)) { // If module is not activated
2937  print '<a href="#" class="classfortooltip" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled", $module).'"><strike>'.$langs->trans("ApiExplorer").'</strike></a>';
2938  } else {
2939  print '<a href="'.DOL_URL_ROOT.'/api/index.php/explorer/" target="apiexplorer">'.$langs->trans("ApiExplorer").'</a>';
2940  }
2941  } else {
2942  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>';
2943  }
2944  // PHPUnit
2945  print '<br>';
2946  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>';
2947  if (dol_is_file($realpathtophpunit)) {
2948  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>';
2949  print ' ';
2950  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>';
2951  } else {
2952  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>';
2953  }
2954  print '<br>';
2955 
2956  print '<br>';
2957 
2958  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>';
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($pathtolib).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
2960  print '<br>';
2961  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>';
2962  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>';
2963  print '<br>';
2964 
2965  print '<br>';
2966  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>';
2967  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>';
2968  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>';
2969  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
2970  print '<br>';
2971  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>';
2972  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>';
2973  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
2974  print '<br>';
2975  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>';
2976  if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
2977  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>';
2978  print ' ';
2979  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>';
2980  print ' &nbsp; ';
2981  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>';
2982  } else {
2983  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>';
2984  }
2985  //print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("RunSql").'</a>';
2986  print '<br>';
2987  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>';
2988  if (dol_is_file($realpathtosqlextra) && dol_is_file($realpathtosqlextrakey)) {
2989  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>';
2990  print ' ';
2991  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>';
2992  } else {
2993  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>';
2994  }
2995  print '<br>';
2996  print '</div>';
2997 
2998  print '<div class="fichehalfleft smallxxxx">';
2999  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>';
3000  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>';
3001  print '<br>';
3002  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>';
3003  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>';
3004  print '<br>';
3005  // Page contact
3006  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>';
3007  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>';
3008  if (dol_is_file($realpathtocontact)) {
3009  print ' ';
3010  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>';
3011  } else {
3012  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>';
3013  }
3014  print '<br>';
3015  // Page document
3016  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>';
3017  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>';
3018  if (dol_is_file($realpathtodocument)) {
3019  print ' ';
3020  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>';
3021  } else {
3022  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>';
3023  }
3024  print '<br>';
3025  // Page notes
3026  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>';
3027  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>';
3028  if (dol_is_file($realpathtonote)) {
3029  print ' ';
3030  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>';
3031  } else {
3032  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>';
3033  }
3034  print '<br>';
3035  // Page agenda
3036  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>';
3037  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>';
3038  if (dol_is_file($realpathtoagenda)) {
3039  print ' ';
3040  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>';
3041  } else {
3042  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>';
3043  }
3044  print '<br>';
3045  print '<br>';
3046 
3047  print '</div>';
3048 
3049  print '<br><br><br>';
3050 
3051  if (!empty($tmpobject)) {
3052  $reflector = new ReflectionClass($tabobj);
3053  $reflectorproperties = $reflector->getProperties(); // Can also use get_object_vars
3054  $reflectorpropdefault = $reflector->getDefaultProperties(); // Can also use get_object_vars
3055  //$propstat = $reflector->getStaticProperties();
3056  //var_dump($reflectorpropdefault);
3057 
3058  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3059  print '<input type="hidden" name="token" value="'.newToken().'">';
3060  print '<input type="hidden" name="action" value="addproperty">';
3061  print '<input type="hidden" name="tab" value="objects">';
3062  print '<input type="hidden" name="page_y" value="">';
3063  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module.($forceddirread ? '@'.$dirread : '')).'">';
3064  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
3065 
3066  print '<input class="button smallpaddingimp" type="submit" name="regenerateclasssql" value="'.$langs->trans("RegenerateClassAndSql").'">';
3067  print '<br><br>';
3068 
3069  print load_fiche_titre($langs->trans("ObjectProperties"), '', '');
3070 
3071  print '<!-- Table with properties of object -->'."\n";
3072  print '<div class="div-table-responsive">';
3073  print '<table class="noborder small">';
3074  print '<tr class="liste_titre">';
3075  print '<th class="none">';
3076 
3077  $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>';
3078  print $form->textwithpicto($langs->trans("Code"), $htmltext, 1, 'help', 'extracss', 0, 3, 'propertyhelp');
3079 
3080  print '</th>';
3081  print '<th>';
3082  print $form->textwithpicto($langs->trans("Label"), $langs->trans("YouCanUseTranslationKey"));
3083  print '</th>';
3084  print '<th>'.$form->textwithpicto($langs->trans("Type"), $langs->trans("TypeOfFieldsHelpIntro").'<br><br>'.$langs->trans("TypeOfFieldsHelp"), 1, 'help', 'extracss', 0, 3, 'typehelp').'</th>';
3085  print '<th>'.$form->textwithpicto($langs->trans("ArrayOfKeyValues"), $langs->trans("ArrayOfKeyValuesDesc")).'</th>';
3086  print '<th class="center">'.$form->textwithpicto($langs->trans("NotNull"), $langs->trans("NotNullDesc")).'</th>';
3087  print '<th class="center">'.$langs->trans("DefaultValue").'</th>';
3088  print '<th class="center">'.$langs->trans("DatabaseIndex").'</th>';
3089  print '<th class="center">'.$form->textwithpicto($langs->trans("ForeignKey"), $langs->trans("ForeignKeyDesc"), 1, 'help', 'extracss', 0, 3, 'foreignkeyhelp').'</th>';
3090  print '<th class="right">'.$langs->trans("Position").'</th>';
3091  print '<th class="center">'.$form->textwithpicto($langs->trans("Enabled"), $langs->trans("EnabledDesc"), 1, 'help', 'extracss', 0, 3, 'enabledhelp').'</th>';
3092  print '<th class="center">'.$form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'<br><br>'.$langs->trans("ItCanBeAnExpression"), 1, 'help', 'extracss', 0, 3, 'visiblehelp').'</th>';
3093  print '<th class="center">'.$langs->trans("NotEditable").'</th>';
3094  print '<th class="center">'.$langs->trans("AlwaysEditable").'</th>';
3095  print '<th class="center">'.$form->textwithpicto($langs->trans("SearchAll"), $langs->trans("SearchAllDesc")).'</th>';
3096  print '<th class="center">'.$form->textwithpicto($langs->trans("IsAMeasure"), $langs->trans("IsAMeasureDesc")).'</th>';
3097  print '<th class="center">'.$langs->trans("CSSClass").'</th>';
3098  print '<th class="center">'.$langs->trans("CSSViewClass").'</th>';
3099  print '<th class="center">'.$langs->trans("CSSListClass").'</th>';
3100  print '<th>'.$langs->trans("KeyForTooltip").'</th>';
3101  print '<th class="center">'.$langs->trans("ShowOnCombobox").'</th>';
3102  //print '<th class="center">'.$langs->trans("Disabled").'</th>';
3103  print '<th>'.$form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")).'</th>';
3104  print '<th>'.$langs->trans("Comment").'</th>';
3105  print '<th class="none"></th>';
3106  print '</tr>';
3107 
3108  // We must use $reflectorpropdefault['fields'] to get list of fields because $tmpobject->fields may have been
3109  // modified during the constructor and we want value into head of class before constructor is called.
3110  //$properties = dol_sort_array($tmpobject->fields, 'position');
3111  $properties = dol_sort_array($reflectorpropdefault['fields'], 'position');
3112 
3113  if (!empty($properties)) {
3114  // Line to add a property
3115  print '<tr>';
3116  print '<td class="none"><input type="text" class="maxwidth75" name="propname" value="'.dol_escape_htmltag(GETPOST('propname', 'alpha')).'"></td>';
3117  print '<td><input type="text" class="maxwidth75" name="proplabel" value="'.dol_escape_htmltag(GETPOST('proplabel', 'alpha')).'"></td>';
3118  print '<td><input type="text" class="maxwidth75" name="proptype" value="'.dol_escape_htmltag(GETPOST('proptype', 'alpha')).'"></td>';
3119  print '<td><input type="text" class="maxwidth75" name="proparrayofkeyval" value="'.dol_escape_htmltag(GETPOST('proparrayofkeyval', 'restricthtml')).'"></td>';
3120  print '<td class="center"><input type="text" class="center maxwidth50" name="propnotnull" value="'.dol_escape_htmltag(GETPOST('propnotnull', 'alpha')).'"></td>';
3121  print '<td><input type="text" class="center maxwidth50" name="propdefault" value="'.dol_escape_htmltag(GETPOST('propdefault', 'alpha')).'"></td>';
3122  print '<td class="center"><input type="text" class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag(GETPOST('propindex', 'alpha')).'"></td>';
3123  print '<td class="center"><input type="text" class="maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag(GETPOST('propforeignkey', 'alpha')).'"></td>';
3124  print '<td class="right"><input type="text" class="right" size="2" name="propposition" value="'.dol_escape_htmltag(GETPOST('propposition', 'alpha')).'"></td>';
3125  print '<td class="center"><input type="text" class="center maxwidth50" name="propenabled" value="'.dol_escape_htmltag(GETPOST('propenabled', 'alpha')).'"></td>';
3126  print '<td class="center"><input type="text" class="center maxwidth50" name="propvisible" value="'.dol_escape_htmltag(GETPOST('propvisible', 'alpha')).'"></td>';
3127  print '<td class="center"><input type="text" class="center maxwidth50" name="propnoteditable" value="'.dol_escape_htmltag(GETPOST('propnoteditable', 'alpha')).'"></td>';
3128  print '<td class="center"><input type="text" class="center maxwidth50" name="propalwayseditable" value="'.dol_escape_htmltag(GETPOST('propalwayseditable', 'alpha')).'"></td>';
3129  print '<td class="center"><input type="text" class="center maxwidth50" name="propsearchall" value="'.dol_escape_htmltag(GETPOST('propsearchall', 'alpha')).'"></td>';
3130  print '<td class="center"><input type="text" class="center maxwidth50" name="propisameasure" value="'.dol_escape_htmltag(GETPOST('propisameasure', 'alpha')).'"></td>';
3131  print '<td class="center"><input type="text" class="maxwidth50" name="propcss" value="'.dol_escape_htmltag(GETPOST('propcss', 'alpha')).'"></td>';
3132  print '<td class="center"><input type="text" class="maxwidth50" name="propcssview" value="'.dol_escape_htmltag(GETPOST('propcssview', 'alpha')).'"></td>';
3133  print '<td class="center"><input type="text" class="maxwidth50" name="propcsslist" value="'.dol_escape_htmltag(GETPOST('propcsslist', 'alpha')).'"></td>';
3134  print '<td><input type="text" size="2" name="prophelp" value="'.dol_escape_htmltag(GETPOST('prophelp', 'alpha')).'"></td>';
3135  print '<td class="center"><input type="text" class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag(GETPOST('propshowoncombobox', 'alpha')).'"></td>';
3136  //print '<td class="center"><input type="text" size="2" name="propdisabled" value="'.dol_escape_htmltag(GETPOST('propdisabled', 'alpha')).'"></td>';
3137  print '<td><input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag(GETPOST('propvalidate', 'alpha')).'"></td>';
3138  print '<td><input class="text maxwidth100" name="propcomment" value="'.dol_escape_htmltag(GETPOST('propcomment', 'alpha')).'"></td>';
3139  print '<td class="center tdstickyright tdstickyghostwhite">';
3140  print '<input type="submit" class="button" name="add" value="'.$langs->trans("Add").'">';
3141  print '</td></tr>';
3142 
3143  // List of existing properties
3144  foreach ($properties as $propkey => $propval) {
3145  /* If from Reflection
3146  if ($propval->class == $tabobj)
3147  {
3148  $propname=$propval->getName();
3149  $comment=$propval->getDocComment();
3150  $type=gettype($tmpobject->$propname);
3151  $default=$propdefault[$propname];
3152  // Discard generic properties
3153  if (in_array($propname, array('element', 'childtables', 'table_element', 'table_element_line', 'class_element_line', 'ismultientitymanaged'))) continue;
3154 
3155  // Keep or not lines
3156  if (in_array($propname, array('fk_element', 'lines'))) continue;
3157  }*/
3158 
3159  $propname = $propkey;
3160  $proplabel = $propval['label'];
3161  $proptype = $propval['type'];
3162  $proparrayofkeyval = !empty($propval['arrayofkeyval'])?$propval['arrayofkeyval']:'';
3163  $propnotnull = !empty($propval['notnull']) ? $propval['notnull'] : '0';
3164  $propdefault = !empty($propval['default'])?$propval['default']:'';
3165  $propindex = !empty($propval['index'])?$propval['index']:'';
3166  $propforeignkey = !empty($propval['foreignkey'])?$propval['foreignkey']:'';
3167  $propposition = $propval['position'];
3168  $propenabled = $propval['enabled'];
3169  $propvisible = $propval['visible'];
3170  $propnoteditable = !empty($propval['noteditable'])?$propval['noteditable']:0;
3171  $propalwayseditable = !empty($propval['alwayseditable'])?$propval['alwayseditable']:0;
3172  $propsearchall = !empty($propval['searchall'])?$propval['searchall']:0;
3173  $propisameasure = !empty($propval['isameasure'])?$propval['isameasure']:0;
3174  $propcss = !empty($propval['css'])?$propval['css']:'';
3175  $propcssview = !empty($propval['cssview'])?$propval['cssview']:'';
3176  $propcsslist = !empty($propval['csslist'])?$propval['csslist']:'';
3177  $prophelp = !empty($propval['help'])?$propval['help']:'';
3178  $propshowoncombobox = !empty($propval['showoncombobox'])?$propval['showoncombobox']:0;
3179  //$propdisabled=$propval['disabled'];
3180  $propvalidate = !empty($propval['validate'])?$propval['validate']:0;
3181  $propcomment = !empty($propval['comment'])?$propval['comment']:'';
3182 
3183  print '<tr class="oddeven">';
3184 
3185  print '<td class="tdsticky tdstickygray">';
3186  print dol_escape_htmltag($propname);
3187  print '</td>';
3188  print '<td>';
3189  print dol_escape_htmltag($proplabel);
3190  print '</td>';
3191  if ($action == 'editproperty' && $propname == $propertykey) {
3192  print '<td class="tdoverflowmax200">';
3193  print '<input type="hidden" name="propname" value="'.dol_escape_htmltag($propname).'">';
3194  print '<input type="hidden" name="proplabel" value="'.dol_escape_htmltag($proplabel).'">';
3195  print '<input name="proptype" value="'.dol_escape_htmltag($proptype).'"></input>';
3196  print '</td>';
3197  print '<td class="tdoverflowmax200">';
3198  print '<input name="proparrayofkeyval" value="';
3199  if (isset($proparrayofkeyval)) {
3200  if (is_array($proparrayofkeyval) || $proparrayofkeyval != '') {
3201  print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
3202  }
3203  }
3204  print '">';
3205  print '</input>';
3206  print '</td>';
3207  print '<td>';
3208  print '<input class="center width50" name="propnotnull" value="'.dol_escape_htmltag($propnotnull).'">';
3209  print '</td>';
3210  print '<td>';
3211  print '<input class="maxwidth50" name="propdefault" value="'.dol_escape_htmltag($propdefault).'">';
3212  print '</td>';
3213  print '<td class="center">';
3214  print '<input class="center maxwidth50" name="propindex" value="'.dol_escape_htmltag($propindex).'">';
3215  print '</td>';
3216  print '<td>';
3217  print '<input class="center maxwidth100" name="propforeignkey" value="'.dol_escape_htmltag($propforeignkey).'">';
3218  print '</td>';
3219  print '<td>';
3220  print '<input class="right width50" name="propposition" value="'.dol_escape_htmltag($propposition).'">';
3221  print '</td>';
3222  print '<td>';
3223  print '<input class="center" name="propenabled" size="2" value="'.dol_escape_htmltag($propenabled).'">';
3224  print '</td>';
3225  print '<td>';
3226  print '<input class="center" name="propvisible" size="2" value="'.dol_escape_htmltag($propvisible).'">';
3227  print '</td>';
3228  print '<td>';
3229  print '<input class="center" name="propnoteditable" size="2" value="'.dol_escape_htmltag($propnoteditable).'">';
3230  print '</td>';
3231  print '<td>';
3232  print '<input class="center" name="propalwayseditable" size="2" value="'.dol_escape_htmltag($propalwayseditable).'">';
3233  print '</td>';
3234  print '<td>';
3235  print '<input class="center" name="propsearchall" size="2" value="'.dol_escape_htmltag($propsearchall).'">';
3236  print '</td>';
3237  print '<td>';
3238  print '<input class="center" name="propisameasure" size="2" value="'.dol_escape_htmltag($propisameasure).'">';
3239  print '</td>';
3240  print '<td>';
3241  print '<input class="center maxwidth50" name="propcss" value="'.dol_escape_htmltag($propcss).'">';
3242  print '</td>';
3243  print '<td>';
3244  print '<input class="center maxwidth50" name="propcssview" value="'.dol_escape_htmltag($propcssview).'">';
3245  print '</td>';
3246  print '<td>';
3247  print '<input class="center maxwidth50" name="propcsslist" value="'.dol_escape_htmltag($propcsslist).'">';
3248  print '</td>';
3249  print '<td>';
3250  print '<input class="maxwidth100" name="prophelp" value="'.dol_escape_htmltag($prophelp).'">';
3251  print '</td>';
3252  print '<td>';
3253  print '<input class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag($propshowoncombobox).'">';
3254  print '</td>';
3255  print '<td>';
3256  print '<input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag($propvalidate).'">';
3257  print '</td>';
3258  print '<td>';
3259  print '<input class="maxwidth100" name="propcomment" value="'.dol_escape_htmltag($propcomment).'">';
3260  print '</td>';
3261  print '<td class="center tdstickyright tdstickyghostwhite">';
3262  print '<input class="reposition button smallpaddingimp" type="submit" name="edit" value="'.$langs->trans("Save").'">';
3263  print '<input class="reposition button button-cancel smallpaddingimp" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
3264  print '</td>';
3265  } else {
3266  print '<td class="tdoverflowmax200">';
3267  print '<span title="'.dol_escape_htmltag($proptype).'">'.dol_escape_htmltag($proptype).'</span>';
3268  print '</td>';
3269  print '<td class="tdoverflowmax200">';
3270  if ($proparrayofkeyval) {
3271  print '<span title="'.dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE)).'">';
3272  print dol_escape_htmltag(json_encode($proparrayofkeyval, JSON_UNESCAPED_UNICODE));
3273  print '</span>';
3274  }
3275  print '</td>';
3276  print '<td class="center">';
3277  print dol_escape_htmltag($propnotnull);
3278  print '</td>';
3279  print '<td>';
3280  print dol_escape_htmltag($propdefault);
3281  print '</td>';
3282  print '<td class="center">';
3283  print $propindex ? '1' : '';
3284  print '</td>';
3285  print '<td class="center">';
3286  print $propforeignkey ? dol_escape_htmltag($propforeignkey) : '';
3287  print '</td>';
3288  print '<td class="right">';
3289  print dol_escape_htmltag($propposition);
3290  print '</td>';
3291  print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
3292  print $propenabled ? dol_escape_htmltag($propenabled) : '';
3293  print '</td>';
3294  // Visibility
3295  print '<td class="center tdoverflowmax100" title="'.($propvisible ? dol_escape_htmltag($propvisible) : '0').'">';
3296  print $propvisible ? dol_escape_htmltag($propvisible) : '0';
3297  print '</td>';
3298  // Readonly
3299  print '<td class="center tdoverflowmax100" title="'.($propnoteditable ? dol_escape_htmltag($propnoteditable) : '').'">';
3300  print $propnoteditable ? dol_escape_htmltag($propnoteditable) : '';
3301  print '</td>';
3302  print '<td class="center">';
3303  print $propalwayseditable ? dol_escape_htmltag($propalwayseditable) : '';
3304  print '</td>';
3305  print '<td class="center">';
3306  print $propsearchall ? '1' : '';
3307  print '</td>';
3308  print '<td class="center">';
3309  print $propisameasure ? dol_escape_htmltag($propisameasure) : '';
3310  print '</td>';
3311  print '<td class="center tdoverflowmax100" title="'.($propcss ? dol_escape_htmltag($propcss) : '').'">';
3312  print $propcss ? dol_escape_htmltag($propcss) : '';
3313  print '</td>';
3314  print '<td class="center tdoverflowmax100" title="'.($propcssview ? dol_escape_htmltag($propcssview) : '').'">';
3315  print $propcssview ? dol_escape_htmltag($propcssview) : '';
3316  print '</td>';
3317  print '<td class="center tdoverflowmax100" title="'.($propcsslist ? dol_escape_htmltag($propcsslist) : '').'">';
3318  print $propcsslist ? dol_escape_htmltag($propcsslist) : '';
3319  print '</td>';
3320  // Key for tooltop
3321  print '<td class="tdoverflowmax150" title="'.($prophelp ? dol_escape_htmltag($prophelp) : '').'">';
3322  print $prophelp ? dol_escape_htmltag($prophelp) : '';
3323  print '</td>';
3324  print '<td class="center">';
3325  print $propshowoncombobox ? dol_escape_htmltag($propshowoncombobox) : '';
3326  print '</td>';
3327  /*print '<td class="center">';
3328  print $propdisabled?$propdisabled:'';
3329  print '</td>';*/
3330  print '<td class="center">';
3331  print $propvalidate ? dol_escape_htmltag($propvalidate) : '';
3332  print '</td>';
3333  print '<td class="tdoverflowmax200">';
3334  print '<span title="'.dol_escape_htmltag($propcomment).'">';
3335  print dol_escape_htmltag($propcomment);
3336  print '</span>';
3337  print '</td>';
3338  print '<td class="center tdstickyright tdstickyghostwhite">';
3339  if ($propname != 'rowid') {
3340  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>';
3341  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>';
3342  }
3343  print '</td>';
3344  }
3345  print '</tr>';
3346  }
3347  } else {
3348  if ($tab == 'specifications') {
3349  if ($action != 'editfile' || empty($file)) {
3350  print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
3351  print '<br>';
3352 
3353  $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
3354 
3355  foreach ($specs as $spec) {
3356  $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
3357  $format = 'asciidoc';
3358  if (preg_match('/\.md$/i', $spec['name'])) {
3359  $format = 'markdown';
3360  }
3361  print '<span class="fa fa-file-o"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3362  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>';
3363  print '<br>';
3364  }
3365  } else {
3366  // Use MD or asciidoc
3367 
3368  //print $langs->trans("UseAsciiDocFormat").'<br>';
3369 
3370  $fullpathoffile = dol_buildpath($file, 0);
3371 
3372  $content = file_get_contents($fullpathoffile);
3373 
3374  // New module
3375  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3376  print '<input type="hidden" name="token" value="'.newToken().'">';
3377  print '<input type="hidden" name="action" value="savefile">';
3378  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3379  print '<input type="hidden" name="tab" value="'.$tab.'">';
3380  print '<input type="hidden" name="module" value="'.$module.'">';
3381 
3382  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3383  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3384  print '<br>';
3385  print '<center>';
3386  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3387  print ' &nbsp; ';
3388  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3389  print '</center>';
3390 
3391  print '</form>';
3392  }
3393  }
3394  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>';
3395  }
3396  print '</table>';
3397  print '</div>';
3398 
3399  print '</form>';
3400  } else {
3401  print '<span class="warning">'.$langs->trans('Failed to init the object with the new '.$tabobj.'($db)').'</warning>';
3402  }
3403  } catch (Exception $e) {
3404  print $e->getMessage();
3405  }
3406  } else {
3407  if (empty($forceddirread)) {
3408  $fullpathoffile = dol_buildpath($file, 0);
3409  } else {
3410  $fullpathoffile = $dirread.'/'.$file;
3411  }
3412 
3413  $content = file_get_contents($fullpathoffile);
3414 
3415  // New module
3416  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3417  print '<input type="hidden" name="token" value="'.newToken().'">';
3418  print '<input type="hidden" name="action" value="savefile">';
3419  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3420  print '<input type="hidden" name="tab" value="'.$tab.'">';
3421  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
3422  print '<input type="hidden" name="module" value="'.$module.($forceddirread ? '@'.$dirread : '').'">';
3423 
3424  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3425  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3426  print '<br>';
3427  print '<center>';
3428  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3429  print ' &nbsp; ';
3430  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3431  print '</center>';
3432 
3433  print '</form>';
3434  }
3435  }
3436 
3437  print dol_get_fiche_end(); // Level 3
3438  }
3439 
3440  if ($tab == 'dictionaries') {
3441  print '<!-- tab=dictionaries -->'."\n";
3442  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3443 
3444  $dicts = $moduleobj->dictionaries;
3445 
3446  if ($action != 'editfile' || empty($file)) {
3447  print '<span class="opacitymedium">';
3448  $htmlhelp = $langs->trans("DictionariesDefDescTooltip", '{s1}');
3449  $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/dict.php">'.$langs->trans('Setup').' - '.$langs->trans('Dictionaries').'</a>', $htmlhelp);
3450  print $form->textwithpicto($langs->trans("DictionariesDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
3451  print '</span>';
3452  print '<br>';
3453 
3454  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3455  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>';
3456  print '<br>';
3457  if (is_array($dicts) && !empty($dicts)) {
3458  print '<span class="fa fa-file-o"></span> '.$langs->trans("LanguageFile").' :</span> ';
3459  print '<strong class="wordbreak">'.$dicts['langs'].'</strong>';
3460  print '<br>';
3461  }
3462 
3463  print '<!-- tab=objects -->'."\n";
3464  $head3 = array();
3465  $h = 0;
3466 
3467  // Dir for module
3468  //$dir = $dirread.'/'.$modulelowercase.'/class';
3469 
3470  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=newdictionary';
3471  $head3[$h][1] = '<span class="valignmiddle text-plus-circle">'.$langs->trans("NewDictionary").'</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
3472  $head3[$h][2] = 'newdictionary';
3473  $h++;
3474 
3475  // Scan for object class files
3476  //$listofobject = dol_dir_list($dir, 'files', 0, '\.class\.php$');
3477 
3478  $firstdicname = '';
3479  if (!empty($dicts['tabname'])) {
3480  foreach ($dicts['tabname'] as $key => $dic) {
3481  $dicname = $dic;
3482  $diclabel = $dicts['tablib'][$key];
3483 
3484  if (empty($firstdicname)) {
3485  $firstdicname = $dicname;
3486  }
3487 
3488  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic='.$dicname;
3489  $head3[$h][1] = $diclabel;
3490  $head3[$h][2] = $dicname;
3491  $h++;
3492  }
3493  }
3494 
3495  if ($h > 1) {
3496  $head3[$h][0] = $_SERVER["PHP_SELF"].'?tab=dictionaries&module='.$module.($forceddirread ? '@'.$dirread : '').'&tabdic=deletedictionary';
3497  $head3[$h][1] = $langs->trans("DangerZone");
3498  $head3[$h][2] = 'deletedictionary';
3499  $h++;
3500  }
3501 
3502  // 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.
3503  if ($tabdic == 'newdicifnodic') {
3504  if ($firstdicname) {
3505  $tabdic = $firstdicname;
3506  } else {
3507  $tabdic = 'newdictionary';
3508  }
3509  }
3510 
3511  print load_fiche_titre($langs->trans("ListOfDictionariesEntries"), '', '');
3512 
3513  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3514  print '<input type="hidden" name="token" value="'.newToken().'">';
3515  print '<input type="hidden" name="action" value="addproperty">';
3516  print '<input type="hidden" name="tab" value="dictionaries">';
3517  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3518  print '<input type="hidden" name="tabdic" value="'.dol_escape_htmltag($tabdic).'">';
3519 
3520  print '<div class="div-table-responsive">';
3521  print '<table class="noborder">';
3522 
3523  print '<tr class="liste_titre">';
3524  print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'thsticky thstickygrey ');
3525  print_liste_field_titre("Table", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3526  print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3527  print_liste_field_titre("SQL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3528  print_liste_field_titre("SQLSort", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3529  print_liste_field_titre("FieldsView", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3530  print_liste_field_titre("FieldsEdit", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3531  print_liste_field_titre("FieldsInsert", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3532  print_liste_field_titre("Rowid", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3533  print_liste_field_titre("Condition", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3534  print "</tr>\n";
3535 
3536  if (!empty($dicts) && is_array($dicts) && !empty($dicts['tabname']) && is_array($dicts['tabname'])) {
3537  $i = 0;
3538  $maxi = count($dicts['tabname']);
3539  while ($i < $maxi) {
3540  print '<tr class="oddeven">';
3541 
3542  print '<td class="tdsticky tdstickygray">';
3543  print ($i + 1);
3544  print '</td>';
3545 
3546  print '<td>';
3547  print $dicts['tabname'][$i];
3548  print '</td>';
3549 
3550  print '<td>';
3551  print $dicts['tablib'][$i];
3552  print '</td>';
3553 
3554  print '<td>';
3555  print $dicts['tabsql'][$i];
3556  print '</td>';
3557 
3558  print '<td>';
3559  print $dicts['tabsqlsort'][$i];
3560  print '</td>';
3561 
3562  print '<td>';
3563  print $dicts['tabfield'][$i];
3564  print '</td>';
3565 
3566  print '<td>';
3567  print $dicts['tabfieldvalue'][$i];
3568  print '</td>';
3569 
3570  print '<td>';
3571  print $dicts['tabfieldinsert'][$i];
3572  print '</td>';
3573 
3574  print '<td class="right">';
3575  print $dicts['tabrowid'][$i];
3576  print '</td>';
3577 
3578  print '<td class="right">';
3579  print $dicts['tabcond'][$i];
3580  print '</td>';
3581 
3582  print '</tr>';
3583  $i++;
3584  }
3585  } else {
3586  print '<tr><td colspan="10"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
3587  }
3588 
3589  print '</table>';
3590  print '</div>';
3591 
3592  print '</form>';
3593 
3594  print dol_get_fiche_head($head3, $tabdic, '', -1, ''); // Level 3
3595 
3596  if ($tabdic == 'newdictionary') {
3597  // New dic tab
3598  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3599  print '<input type="hidden" name="token" value="'.newToken().'">';
3600  print '<input type="hidden" name="action" value="initdic">';
3601  print '<input type="hidden" name="tab" value="dictionaries">';
3602  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3603 
3604  print '<span class="opacitymedium">'.$langs->trans("EnterNameOfDictionaryDesc").'</span><br><br>';
3605 
3606  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>';
3607  //print '<input type="checkbox" name="includerefgeneration" id="includerefgeneration" value="includerefgeneration"> <label for="includerefgeneration">'.$form->textwithpicto($langs->trans("IncludeRefGeneration"), $langs->trans("IncludeRefGenerationHelp")).'</label><br>';
3608  //print '<input type="checkbox" name="includedocgeneration" id="includedocgeneration" value="includedocgeneration"> <label for="includedocgeneration">'.$form->textwithpicto($langs->trans("IncludeDocGeneration"), $langs->trans("IncludeDocGenerationHelp")).'</label><br>';
3609  print '<input type="submit" class="button smallpaddingimp" name="create" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3610  /*print '<br>';
3611  print '<br>';
3612  print '<br>';
3613  print '<span class="opacitymedium">'.$langs->trans("or").'</span>';
3614  print '<br>';
3615  print '<br>';
3616  //print '<input type="checkbox" name="initfromtablecheck"> ';
3617  print $langs->trans("InitStructureFromExistingTable");
3618  print '<input type="text" name="initfromtablename" value="" placeholder="'.$langs->trans("TableName").'">';
3619  print '<input type="submit" class="button smallpaddingimp" name="createtablearray" value="'.dol_escape_htmltag($langs->trans("GenerateCode")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3620  print '<br>';
3621  */
3622  print '</form>';
3623  } elseif ($tabdic == 'deletedictionary') {
3624  // Delete dic tab
3625  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3626  print '<input type="hidden" name="token" value="'.newToken().'">';
3627  print '<input type="hidden" name="action" value="confirm_deleteobject">';
3628  print '<input type="hidden" name="tab" value="dictionaries">';
3629  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3630 
3631  print $langs->trans("EnterNameOfObjectToDeleteDesc").'<br><br>';
3632 
3633  print '<input type="text" name="objectname" value="'.dol_escape_htmltag($modulename).'" placeholder="'.dol_escape_htmltag($langs->trans("ObjectKey")).'">';
3634  print '<input type="submit" class="button smallpaddingimp" name="delete" value="'.dol_escape_htmltag($langs->trans("Delete")).'"'.($dirins ? '' : ' disabled="disabled"').'>';
3635  print '</form>';
3636  } else {
3637  print $langs->trans("FeatureNotYetAvailable");
3638  }
3639 
3640  print dol_get_fiche_end();
3641  } else {
3642  $fullpathoffile = dol_buildpath($file, 0);
3643 
3644  $content = file_get_contents($fullpathoffile);
3645 
3646  // New module
3647  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3648  print '<input type="hidden" name="token" value="'.newToken().'">';
3649  print '<input type="hidden" name="action" value="savefile">';
3650  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3651  print '<input type="hidden" name="tab" value="'.$tab.'">';
3652  print '<input type="hidden" name="module" value="'.$module.'">';
3653 
3654  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3655  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3656  print '<br>';
3657  print '<center>';
3658  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3659  print ' &nbsp; ';
3660  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3661  print '</center>';
3662 
3663  print '</form>';
3664  }
3665  }
3666 
3667  if ($tab == 'menus') {
3668  print '<!-- tab=menus -->'."\n";
3669  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3670 
3671  $menus = $moduleobj->menu;
3672 
3673  if ($action != 'editfile' || empty($file)) {
3674  print '<span class="opacitymedium">';
3675  $htmlhelp = $langs->trans("MenusDefDescTooltip", '{s1}');
3676  $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);
3677  print $form->textwithpicto($langs->trans("MenusDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
3678  print '</span>';
3679  print '<br>';
3680 
3681  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3682  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>';
3683  print '<br>';
3684 
3685  print '<br>';
3686  print load_fiche_titre($langs->trans("ListOfMenusEntries"), '', '');
3687 
3688  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3689  print '<input type="hidden" name="token" value="'.newToken().'">';
3690  print '<input type="hidden" name="action" value="addproperty">';
3691  print '<input type="hidden" name="tab" value="objects">';
3692  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3693  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
3694 
3695  print '<div class="div-table-responsive">';
3696  print '<table class="noborder small">';
3697 
3698  print '<tr class="liste_titre">';
3699  print_liste_field_titre("#", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'thsticky ');
3700  print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3701  print_liste_field_titre("LinkToParentMenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3702  print_liste_field_titre("Title", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3703  print_liste_field_titre("mainmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3704  print_liste_field_titre("leftmenu", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3705  print_liste_field_titre("URL", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->transnoentitiesnoconv('DetailUrl'));
3706  print_liste_field_titre("LanguageFile", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3707  print_liste_field_titre("Position", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'right ');
3708  print_liste_field_titre("Enabled", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'center ', $langs->trans('DetailEnabled'));
3709  print_liste_field_titre("Rights", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailRight'));
3710  print_liste_field_titre("Target", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, '', $langs->trans('DetailTarget'));
3711  print_liste_field_titre("MenuForUsers", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder, 'right ', $langs->trans('DetailUser'));
3712  print "</tr>\n";
3713 
3714  if (count($menus)) {
3715  $i = 0;
3716  foreach ($menus as $menu) {
3717  $i++;
3718 
3719  print '<tr class="oddeven">';
3720 
3721  print '<td class="tdsticky tdstickygray">';
3722  print $i;
3723  print '</td>';
3724 
3725  print '<td>';
3726  print dol_escape_htmltag($menu['type']);
3727  print '</td>';
3728 
3729  print '<td>';
3730  print dol_escape_htmltag($menu['fk_menu']);
3731  print '</td>';
3732 
3733  print '<td>';
3734  print dol_escape_htmltag($menu['titre']);
3735  print '</td>';
3736 
3737  print '<td>';
3738  print dol_escape_htmltag($menu['mainmenu']);
3739  print '</td>';
3740 
3741  print '<td>';
3742  print dol_escape_htmltag($menu['leftmenu']);
3743  print '</td>';
3744 
3745  print '<td class="tdoverflowmax300" title="'.dol_escape_htmltag($menu['url']).'">';
3746  print dol_escape_htmltag($menu['url']);
3747  print '</td>';
3748 
3749  print '<td>';
3750  print dol_escape_htmltag($menu['langs']);
3751  print '</td>';
3752 
3753  print '<td class="right">';
3754  print dol_escape_htmltag($menu['position']);
3755  print '</td>';
3756 
3757  print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['enabled']).'">';
3758  print dol_escape_htmltag($menu['enabled']);
3759  print '</td>';
3760 
3761  print '<td class="center tdoverflowmax200" title="'.dol_escape_htmltag($menu['perms']).'">';
3762  print dol_escape_htmltag($menu['perms']);
3763  print '</td>';
3764 
3765  print '<td>';
3766  print dol_escape_htmltag($menu['target']);
3767  print '</td>';
3768 
3769  print '<td class="right">';
3770  if ($menu['user'] == 2) {
3771  print $langs->trans("AllMenus");
3772  } elseif ($menu['user'] == 0) {
3773  print $langs->trans('Internal');
3774  } elseif ($menu['user'] == 1) {
3775  print $langs->trans('External');
3776  } else {
3777  print $menu['user']; // should not happen
3778  }
3779  print '</td>';
3780 
3781  print '</tr>';
3782  }
3783  } else {
3784  print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
3785  }
3786 
3787  print '</table>';
3788  print '</div>';
3789 
3790  print '</form>';
3791  } else {
3792  $fullpathoffile = dol_buildpath($file, 0);
3793 
3794  $content = file_get_contents($fullpathoffile);
3795 
3796  // New module
3797  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3798  print '<input type="hidden" name="token" value="'.newToken().'">';
3799  print '<input type="hidden" name="action" value="savefile">';
3800  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3801  print '<input type="hidden" name="tab" value="'.$tab.'">';
3802  print '<input type="hidden" name="module" value="'.$module.'">';
3803 
3804  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3805  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3806  print '<br>';
3807  print '<center>';
3808  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3809  print ' &nbsp; ';
3810  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3811  print '</center>';
3812 
3813  print '</form>';
3814  }
3815  }
3816 
3817  if ($tab == 'permissions') {
3818  print '<!-- tab=permissions -->'."\n";
3819  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3820 
3821  $perms = $moduleobj->rights;
3822 
3823  if ($action != 'editfile' || empty($file)) {
3824  print '<span class="opacitymedium">';
3825  $htmlhelp = $langs->trans("PermissionsDefDescTooltip", '{s1}');
3826  $htmlhelp = str_replace('{s1}', '<a target="adminbis" class="nofocusvisible" href="'.DOL_URL_ROOT.'/admin/perms.php">'.$langs->trans('DefaultRights').'</a>', $htmlhelp);
3827  print $form->textwithpicto($langs->trans("PermissionsDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
3828  print '</span>';
3829  print '<br>';
3830 
3831  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3832  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>';
3833  print '<br>';
3834 
3835  print '<br>';
3836  print load_fiche_titre($langs->trans("ListOfPermissionsDefined"), '', '');
3837 
3838  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3839  print '<input type="hidden" name="token" value="'.newToken().'">';
3840  print '<input type="hidden" name="action" value="addproperty">';
3841  print '<input type="hidden" name="tab" value="objects">';
3842  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
3843  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
3844 
3845  print '<div class="div-table-responsive">';
3846  print '<table class="noborder">';
3847 
3848  print '<tr class="liste_titre">';
3849  print_liste_field_titre("ID", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3850  print_liste_field_titre("Label", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3851  print_liste_field_titre("Permission", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3852  print_liste_field_titre("", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
3853  print "</tr>\n";
3854 
3855  if (count($perms)) {
3856  foreach ($perms as $perm) {
3857  print '<tr class="oddeven">';
3858 
3859  print '<td>';
3860  print $perm[0];
3861  print '</td>';
3862 
3863  print '<td>';
3864  print $langs->trans($perm[1]);
3865  print '</td>';
3866 
3867  print '<td>';
3868  print $perm[4];
3869  print '</td>';
3870 
3871  print '<td>';
3872  print $perm[5];
3873  print '</td>';
3874 
3875  print '</tr>';
3876  }
3877  } else {
3878  print '<tr><td colspan="4"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
3879  }
3880 
3881  print '</table>';
3882  print '</div>';
3883 
3884  print '</form>';
3885  } else {
3886  $fullpathoffile = dol_buildpath($file, 0);
3887 
3888  $content = file_get_contents($fullpathoffile);
3889 
3890  // New module
3891  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3892  print '<input type="hidden" name="token" value="'.newToken().'">';
3893  print '<input type="hidden" name="action" value="savefile">';
3894  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3895  print '<input type="hidden" name="tab" value="'.$tab.'">';
3896  print '<input type="hidden" name="module" value="'.$module.'">';
3897 
3898  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3899  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3900  print '<br>';
3901  print '<center>';
3902  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3903  print ' &nbsp; ';
3904  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3905  print '</center>';
3906 
3907  print '</form>';
3908  }
3909  }
3910 
3911  if ($tab == 'hooks') {
3912  print '<!-- tab=hooks -->'."\n";
3913  if ($action != 'editfile' || empty($file)) {
3914  print '<span class="opacitymedium">'.$langs->trans("HooksDefDesc").'</span><br>';
3915  print '<br>';
3916 
3917  print '<table>';
3918 
3919  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3920  print '<tr><td>';
3921  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3922  print '</td><td>';
3923  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>';
3924  print '</td></tr>';
3925 
3926  print '<tr><td>';
3927  $pathtohook = strtolower($module).'/class/actions_'.strtolower($module).'.class.php';
3928  print '<span class="fa fa-file-o"></span> '.$langs->trans("HooksFile").' : ';
3929  if (dol_is_file($dirins.'/'.$pathtohook)) {
3930  print '<strong class="wordbreak">'.$pathtohook.'</strong>';
3931  print '</td>';
3932  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> ';
3933  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>';
3934  } else {
3935  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
3936  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>';
3937  print '<td></td>';
3938  }
3939  print '</tr>';
3940  } else {
3941  $fullpathoffile = dol_buildpath($file, 0);
3942 
3943  $content = file_get_contents($fullpathoffile);
3944 
3945  // New module
3946  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
3947  print '<input type="hidden" name="token" value="'.newToken().'">';
3948  print '<input type="hidden" name="action" value="savefile">';
3949  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
3950  print '<input type="hidden" name="tab" value="'.$tab.'">';
3951  print '<input type="hidden" name="module" value="'.$module.'">';
3952 
3953  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
3954  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
3955  print '<br>';
3956  print '<center>';
3957  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
3958  print ' &nbsp; ';
3959  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
3960  print '</center>';
3961 
3962  print '</form>';
3963  }
3964  }
3965 
3966  if ($tab == 'triggers') {
3967  print '<!-- tab=triggers -->'."\n";
3968  require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
3969 
3970  $interfaces = new Interfaces($db);
3971  $triggers = $interfaces->getTriggersList(array('/'.strtolower($module).'/core/triggers'));
3972 
3973  if ($action != 'editfile' || empty($file)) {
3974  print '<span class="opacitymedium">'.$langs->trans("TriggerDefDesc").'</span><br>';
3975  print '<br>';
3976 
3977  print '<table>';
3978 
3979  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
3980  print '<tr><td>';
3981  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3982  print '</td><td>';
3983  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>';
3984  print '</td></tr>';
3985 
3986  if (!empty($triggers)) {
3987  foreach ($triggers as $trigger) {
3988  $pathtofile = $trigger['relpath'];
3989 
3990  print '<tr><td>';
3991  print '<span class="fa fa-file-o"></span> '.$langs->trans("TriggersFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
3992  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>';
3993  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>';
3994  print '</tr>';
3995  }
3996  } else {
3997  print '<tr><td>';
3998  print '<span class="fa fa-file-o"></span> '.$langs->trans("TriggersFile");
3999  print ' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4000  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>';
4001  print '<td></td>';
4002  print '</tr>';
4003  }
4004 
4005  print '</table>';
4006  } else {
4007  $fullpathoffile = dol_buildpath($file, 0);
4008 
4009  $content = file_get_contents($fullpathoffile);
4010 
4011  // New module
4012  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4013  print '<input type="hidden" name="token" value="'.newToken().'">';
4014  print '<input type="hidden" name="action" value="savefile">';
4015  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4016  print '<input type="hidden" name="tab" value="'.$tab.'">';
4017  print '<input type="hidden" name="module" value="'.$module.'">';
4018 
4019  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4020  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4021  print '<br>';
4022  print '<center>';
4023  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4024  print ' &nbsp; ';
4025  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4026  print '</center>';
4027 
4028  print '</form>';
4029  }
4030  }
4031 
4032  if ($tab == 'css') {
4033  print '<!-- tab=css -->'."\n";
4034  if ($action != 'editfile' || empty($file)) {
4035  print '<span class="opacitymedium">'.$langs->trans("CSSDesc").'</span><br>';
4036  print '<br>';
4037 
4038  print '<table>';
4039 
4040  print '<tr><td>';
4041  $pathtohook = strtolower($module).'/css/'.strtolower($module).'.css.php';
4042  print '<span class="fa fa-file-o"></span> '.$langs->trans("CSSFile").' : ';
4043  if (dol_is_file($dirins.'/'.$pathtohook)) {
4044  print '<strong class="wordbreak">'.$pathtohook.'</strong>';
4045  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>';
4046  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>';
4047  } else {
4048  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4049  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>';
4050  }
4051  print '</tr>';
4052  } else {
4053  $fullpathoffile = dol_buildpath($file, 0);
4054 
4055  $content = file_get_contents($fullpathoffile);
4056 
4057  // New module
4058  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4059  print '<input type="hidden" name="token" value="'.newToken().'">';
4060  print '<input type="hidden" name="action" value="savefile">';
4061  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4062  print '<input type="hidden" name="tab" value="'.$tab.'">';
4063  print '<input type="hidden" name="module" value="'.$module.'">';
4064 
4065  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4066  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4067  print '<br>';
4068  print '<center>';
4069  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4070  print ' &nbsp; ';
4071  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4072  print '</center>';
4073 
4074  print '</form>';
4075  }
4076  }
4077 
4078  if ($tab == 'js') {
4079  print '<!-- tab=js -->'."\n";
4080  if ($action != 'editfile' || empty($file)) {
4081  print '<span class="opacitymedium">'.$langs->trans("JSDesc").'</span><br>';
4082  print '<br>';
4083 
4084  print '<table>';
4085 
4086  print '<tr><td>';
4087  $pathtohook = strtolower($module).'/js/'.strtolower($module).'.js.php';
4088  print '<span class="fa fa-file-o"></span> '.$langs->trans("JSFile").' : ';
4089  if (dol_is_file($dirins.'/'.$pathtohook)) {
4090  print '<strong class="wordbreak">'.$pathtohook.'</strong>';
4091  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>';
4092  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>';
4093  } else {
4094  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4095  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>';
4096  }
4097  print '</tr>';
4098  } else {
4099  $fullpathoffile = dol_buildpath($file, 0);
4100 
4101  $content = file_get_contents($fullpathoffile);
4102 
4103  // New module
4104  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4105  print '<input type="hidden" name="token" value="'.newToken().'">';
4106  print '<input type="hidden" name="action" value="savefile">';
4107  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4108  print '<input type="hidden" name="tab" value="'.$tab.'">';
4109  print '<input type="hidden" name="module" value="'.$module.'">';
4110 
4111  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4112  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4113  print '<br>';
4114  print '<center>';
4115  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4116  print ' &nbsp; ';
4117  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4118  print '</center>';
4119 
4120  print '</form>';
4121  }
4122  }
4123 
4124  if ($tab == 'widgets') {
4125  print '<!-- tab=widgets -->'."\n";
4126  require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
4127 
4128  $widgets = ModeleBoxes::getWidgetsList(array('/'.strtolower($module).'/core/boxes'));
4129 
4130  if ($action != 'editfile' || empty($file)) {
4131  print '<span class="opacitymedium">'.$langs->trans("WidgetDesc").'</span><br>';
4132  print '<br>';
4133 
4134  print '<table>';
4135  if (!empty($widgets)) {
4136  foreach ($widgets as $widget) {
4137  $pathtofile = $widget['relpath'];
4138 
4139  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("WidgetFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4140  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>';
4141  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>';
4142  print '</tr>';
4143  }
4144  } else {
4145  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("WidgetFile").' : <span class="opacitymedium">'.$langs->trans("NoWidget").'</span>';
4146  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>';
4147  print '</td></tr>';
4148  }
4149  print '</table>';
4150  } else {
4151  $fullpathoffile = dol_buildpath($file, 0);
4152 
4153  $content = file_get_contents($fullpathoffile);
4154 
4155  // New module
4156  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4157  print '<input type="hidden" name="token" value="'.newToken().'">';
4158  print '<input type="hidden" name="action" value="savefile">';
4159  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4160  print '<input type="hidden" name="tab" value="'.$tab.'">';
4161  print '<input type="hidden" name="module" value="'.$module.'">';
4162 
4163  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4164  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4165  print '<br>';
4166  print '<center>';
4167  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4168  print ' &nbsp; ';
4169  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4170  print '</center>';
4171 
4172  print '</form>';
4173  }
4174  }
4175 
4176  if ($tab == 'exportimport') {
4177  print '<!-- tab=exportimport -->'."\n";
4178  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4179 
4180  $exportlist = $moduleobj->export_label;
4181  $importlist = $moduleobj->import_label;
4182 
4183  if ($action != 'editfile' || empty($file)) {
4184  print '<span class="opacitymedium">'.$langs->transnoentities('ImportExportProfiles').'</span><br>';
4185  print '<br>';
4186 
4187  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4188  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>';
4189  print '<br>';
4190  } else {
4191  $fullpathoffile = dol_buildpath($file, 0);
4192 
4193  $content = file_get_contents($fullpathoffile);
4194 
4195  // New module
4196  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4197  print '<input type="hidden" name="token" value="'.newToken().'">';
4198  print '<input type="hidden" name="action" value="savefile">';
4199  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4200  print '<input type="hidden" name="tab" value="'.$tab.'">';
4201  print '<input type="hidden" name="module" value="'.$module.'">';
4202 
4203  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4204  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4205  print '<br>';
4206  print '<center>';
4207  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4208  print ' &nbsp; ';
4209  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4210  print '</center>';
4211 
4212  print '</form>';
4213  }
4214  }
4215 
4216  if ($tab == 'cli') {
4217  print '<!-- tab=cli -->'."\n";
4218  $clifiles = array();
4219  $i = 0;
4220 
4221  $dircli = array('/'.strtolower($module).'/scripts');
4222 
4223  foreach ($dircli as $reldir) {
4224  $dir = dol_buildpath($reldir, 0);
4225  $newdir = dol_osencode($dir);
4226 
4227  // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
4228  if (!is_dir($newdir)) {
4229  continue;
4230  }
4231 
4232  $handle = opendir($newdir);
4233  if (is_resource($handle)) {
4234  while (($tmpfile = readdir($handle)) !== false) {
4235  if (is_readable($newdir.'/'.$file) && preg_match('/^(.+)\.php/', $tmpfile, $reg)) {
4236  if (preg_match('/\.back$/', $tmpfile)) {
4237  continue;
4238  }
4239 
4240  $clifiles[$i]['relpath'] = preg_replace('/^\//', '', $reldir).'/'.$tmpfile;
4241 
4242  $i++;
4243  }
4244  }
4245  closedir($handle);
4246  }
4247  }
4248 
4249  if ($action != 'editfile' || empty($file)) {
4250  print '<span class="opacitymedium">'.$langs->trans("CLIDesc").'</span><br>';
4251  print '<br>';
4252 
4253  print '<table>';
4254  if (!empty($clifiles)) {
4255  foreach ($clifiles as $clifile) {
4256  $pathtofile = $clifile['relpath'];
4257 
4258  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("CLIFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4259  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>';
4260  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>';
4261  print '</tr>';
4262  }
4263  } else {
4264  print '<tr><td><span class="fa fa-file-o"></span> '.$langs->trans("CLIFile").' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated"); '</span>';
4265  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>';
4266  print '</td></tr>';
4267  }
4268  print '</table>';
4269  } else {
4270  $fullpathoffile = dol_buildpath($file, 0);
4271 
4272  $content = file_get_contents($fullpathoffile);
4273 
4274  // New module
4275  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4276  print '<input type="hidden" name="token" value="'.newToken().'">';
4277  print '<input type="hidden" name="action" value="savefile">';
4278  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4279  print '<input type="hidden" name="tab" value="'.$tab.'">';
4280  print '<input type="hidden" name="module" value="'.$module.'">';
4281 
4282  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4283  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4284  print '<br>';
4285  print '<center>';
4286  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4287  print ' &nbsp; ';
4288  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4289  print '</center>';
4290 
4291  print '</form>';
4292  }
4293  }
4294 
4295  if ($tab == 'cron') {
4296  print '<!-- tab=cron -->'."\n";
4297  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4298 
4299  $cronjobs = $moduleobj->cronjobs;
4300 
4301  if ($action != 'editfile' || empty($file)) {
4302  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>';
4303  print '<br>';
4304 
4305  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4306  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>';
4307  print '<br>';
4308 
4309  print '<br>';
4310  print load_fiche_titre($langs->trans("CronJobProfiles"), '', '');
4311 
4312  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4313  print '<input type="hidden" name="token" value="'.newToken().'">';
4314  print '<input type="hidden" name="action" value="addproperty">';
4315  print '<input type="hidden" name="tab" value="objects">';
4316  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4317  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4318 
4319  print '<div class="div-table-responsive">';
4320  print '<table class="noborder">';
4321 
4322  print '<tr class="liste_titre">';
4323  print_liste_field_titre("CronLabel", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
4324  print_liste_field_titre("CronTask", '', '', "", $param, '', $sortfield, $sortorder);
4325  print_liste_field_titre("CronFrequency", '', "", "", $param, '', $sortfield, $sortorder);
4326  print_liste_field_titre("StatusAtInstall", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
4327  print_liste_field_titre("Comment", $_SERVER["PHP_SELF"], "", "", $param, '', $sortfield, $sortorder);
4328  print "</tr>\n";
4329 
4330  if (count($cronjobs)) {
4331  foreach ($cronjobs as $cron) {
4332  print '<tr class="oddeven">';
4333 
4334  print '<td>';
4335  print $cron['label'];
4336  print '</td>';
4337 
4338  print '<td>';
4339  if ($cron['jobtype'] == 'method') {
4340  $text = $langs->trans("CronClass");
4341  $texttoshow = $langs->trans('CronModule').': '.$module.'<br>';
4342  $texttoshow .= $langs->trans('CronClass').': '.$cron['class'].'<br>';
4343  $texttoshow .= $langs->trans('CronObject').': '.$cron['objectname'].'<br>';
4344  $texttoshow .= $langs->trans('CronMethod').': '.$cron['method'];
4345  $texttoshow .= '<br>'.$langs->trans('CronArgs').': '.$cron['parameters'];
4346  $texttoshow .= '<br>'.$langs->trans('Comment').': '.$langs->trans($cron['comment']);
4347  } elseif ($cron['jobtype'] == 'command') {
4348  $text = $langs->trans('CronCommand');
4349  $texttoshow = $langs->trans('CronCommand').': '.dol_trunc($cron['command']);
4350  $texttoshow .= '<br>'.$langs->trans('CronArgs').': '.$cron['parameters'];
4351  $texttoshow .= '<br>'.$langs->trans('Comment').': '.$langs->trans($cron['comment']);
4352  }
4353  print $form->textwithpicto($text, $texttoshow, 1);
4354  print '</td>';
4355 
4356  print '<td>';
4357  if ($cron['unitfrequency'] == "60") {
4358  print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Minutes');
4359  }
4360  if ($cron['unitfrequency'] == "3600") {
4361  print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Hours');
4362  }
4363  if ($cron['unitfrequency'] == "86400") {
4364  print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Days');
4365  }
4366  if ($cron['unitfrequency'] == "604800") {
4367  print $langs->trans('CronEach')." ".($cron['frequency'])." ".$langs->trans('Weeks');
4368  }
4369  print '</td>';
4370 
4371  print '<td>';
4372  print $cron['status'];
4373  print '</td>';
4374 
4375  print '<td>';
4376  if (!empty($cron['comment'])) {
4377  print $cron['comment'];
4378  }
4379  print '</td>';
4380 
4381  print '</tr>';
4382  }
4383  } else {
4384  print '<tr><td colspan="5"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
4385  }
4386 
4387  print '</table>';
4388  print '</div>';
4389 
4390  print '</form>';
4391  } else {
4392  $fullpathoffile = dol_buildpath($file, 0);
4393 
4394  $content = file_get_contents($fullpathoffile);
4395 
4396  // New module
4397  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4398  print '<input type="hidden" name="token" value="'.newToken().'">';
4399  print '<input type="hidden" name="action" value="savefile">';
4400  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4401  print '<input type="hidden" name="tab" value="'.$tab.'">';
4402  print '<input type="hidden" name="module" value="'.$module.'">';
4403 
4404  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4405  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4406  print '<br>';
4407  print '<center>';
4408  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4409  print ' &nbsp; ';
4410  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4411  print '</center>';
4412 
4413  print '</form>';
4414  }
4415  }
4416 
4417  if ($tab == 'specifications') {
4418  print '<!-- tab=specifications -->'."\n";
4419  $specs = dol_dir_list(dol_buildpath($modulelowercase.'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
4420 
4421  if ($action != 'editfile' || empty($file)) {
4422  print '<span class="opacitymedium">'.$langs->trans("SpecDefDesc").'</span><br>';
4423  print '<br>';
4424 
4425  print '<table>';
4426  if (is_array($specs) && !empty($specs)) {
4427  foreach ($specs as $spec) {
4428  $pathtofile = $modulelowercase.'/doc/'.$spec['relativename'];
4429  $format = 'asciidoc';
4430  if (preg_match('/\.md$/i', $spec['name'])) {
4431  $format = 'markdown';
4432  }
4433  print '<tr><td>';
4434  print '<span class="fa fa-file-o"></span> '.$langs->trans("SpecificationFile").' : <strong class="wordbreak">'.$pathtofile.'</strong>';
4435  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>';
4436  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>';
4437  print '</tr>';
4438  }
4439  } else {
4440  print '<tr><td>';
4441  print '<span class="fa fa-file-o"></span> '.$langs->trans("SpecificationFile").' : <span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4442  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>';
4443  print '</tr>';
4444  }
4445  print '</table>';
4446  } else {
4447  // Use MD or asciidoc
4448 
4449  //print $langs->trans("UseAsciiDocFormat").'<br>';
4450 
4451  $fullpathoffile = dol_buildpath($file, 0);
4452 
4453  $content = file_get_contents($fullpathoffile);
4454 
4455  // New module
4456  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4457  print '<input type="hidden" name="token" value="'.newToken().'">';
4458  print '<input type="hidden" name="action" value="savefile">';
4459  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4460  print '<input type="hidden" name="tab" value="'.$tab.'">';
4461  print '<input type="hidden" name="module" value="'.$module.'">';
4462 
4463  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4464  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4465  print '<br>';
4466  print '<center>';
4467  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4468  print ' &nbsp; ';
4469  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4470  print '</center>';
4471 
4472  print '</form>';
4473  }
4474 
4475  print '<br><br><br>';
4476 
4477  $FILENAMEDOC = $modulelowercase.'.html';
4478  $FILENAMEDOCPDF = $modulelowercase.'.pdf';
4479  $outputfiledoc = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOC;
4480  $outputfiledocurl = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOC;
4481  $outputfiledocrel = $modulelowercase.'/doc/'.$FILENAMEDOC;
4482  $outputfiledocpdf = dol_buildpath($modulelowercase, 0).'/doc/'.$FILENAMEDOCPDF;
4483  $outputfiledocurlpdf = dol_buildpath($modulelowercase, 1).'/doc/'.$FILENAMEDOCPDF;
4484  $outputfiledocrelpdf = $modulelowercase.'/doc/'.$FILENAMEDOCPDF;
4485 
4486  // HTML
4487  print '<span class="fa fa-file-o"></span> '.$langs->trans("PathToModuleDocumentation", "HTML").' : ';
4488  if (!dol_is_file($outputfiledoc)) {
4489  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4490  } else {
4491  print '<strong>';
4492  print '<a href="'.$outputfiledocurl.'" target="_blank" rel="noopener noreferrer">';
4493  print $outputfiledoc;
4494  print '</a>';
4495  print '</strong>';
4496  print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfiledoc), 'dayhour').')</span>';
4497  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>';
4498  }
4499  print '</strong><br>';
4500 
4501  // PDF
4502  print '<span class="fa fa-file-o"></span> '.$langs->trans("PathToModuleDocumentation", "PDF").' : ';
4503  if (!dol_is_file($outputfiledocpdf)) {
4504  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4505  } else {
4506  print '<strong>';
4507  print '<a href="'.$outputfiledocurlpdf.'" target="_blank" rel="noopener noreferrer">';
4508  print $outputfiledocpdf;
4509  print '</a>';
4510  print '</strong>';
4511  print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfiledocpdf), 'dayhour').')</span>';
4512  print ' <a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?tab='.urlencode($tab).'&module='.$module.($forceddirread ? '@'.$dirread : '').'&action=confirm_removefile&token='.newToken().'&format='.$format.'&file='.urlencode($outputfiledocpdfrel).'">'.img_picto($langs->trans("Delete"), 'delete').'</a>';
4513  }
4514  print '</strong><br>';
4515 
4516  print '<br>';
4517 
4518  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="generatedoc">';
4519  print '<input type="hidden" name="token" value="'.newToken().'">';
4520  print '<input type="hidden" name="action" value="generatedoc">';
4521  print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
4522  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4523  print '<input type="submit" class="button" name="generatedoc" value="'.$langs->trans("BuildDocumentation").'"';
4524  if (!is_array($specs) || empty($specs)) {
4525  print ' disabled="disabled"';
4526  }
4527  print '>';
4528  print '</form>';
4529  }
4530 
4531  if ($tab == 'buildpackage') {
4532  print '<!-- tab=buildpackage -->'."\n";
4533  print '<span class="opacitymedium">'.$langs->trans("BuildPackageDesc").'</span>';
4534  print '<br>';
4535 
4536  if (!class_exists('ZipArchive') && !defined('ODTPHP_PATHTOPCLZIP')) {
4537  print img_warning().' '.$langs->trans("ErrNoZipEngine");
4538  print '<br>';
4539  }
4540 
4541  $modulelowercase = strtolower($module);
4542 
4543  // Zip file to build
4544  $FILENAMEZIP = '';
4545 
4546  // Load module
4547  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4548  dol_include_once($pathtofile);
4549  $class = 'mod'.$module;
4550 
4551  if (class_exists($class)) {
4552  try {
4553  $moduleobj = new $class($db);
4554  } catch (Exception $e) {
4555  $error++;
4556  dol_print_error($db, $e->getMessage());
4557  }
4558  } else {
4559  $error++;
4560  $langs->load("errors");
4561  dol_print_error($db, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
4562  exit;
4563  }
4564 
4565  $arrayversion = explode('.', $moduleobj->version, 3);
4566  if (count($arrayversion)) {
4567  $FILENAMEZIP = "module_".$modulelowercase.'-'.$arrayversion[0].(empty($arrayversion[1]) ? '.0' : '.'.$arrayversion[1]).(empty($arrayversion[2]) ? '' : ".".$arrayversion[2]).".zip";
4568  $outputfilezip = dol_buildpath($modulelowercase, 0).'/bin/'.$FILENAMEZIP;
4569  }
4570 
4571  print '<br>';
4572 
4573  print '<span class="fa fa-file-o"></span> '.$langs->trans("PathToModulePackage").' : ';
4574  if (!dol_is_file($outputfilezip)) {
4575  print '<span class="opacitymedium">'.$langs->trans("FileNotYetGenerated").'</span>';
4576  } else {
4577  $relativepath = $modulelowercase.'/bin/'.$FILENAMEZIP;
4578  print '<strong><a href="'.DOL_URL_ROOT.'/document.php?modulepart=packages&file='.urlencode($relativepath).'">'.$outputfilezip.'</a></strong>';
4579  print ' <span class="opacitymedium">('.$langs->trans("GeneratedOn").' '.dol_print_date(dol_filemtime($outputfilezip), 'dayhour').')</span>';
4580  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>';
4581  }
4582  print '</strong>';
4583 
4584  print '<br>';
4585 
4586  print '<br>';
4587 
4588  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="generatepackage">';
4589  print '<input type="hidden" name="token" value="'.newToken().'">';
4590  print '<input type="hidden" name="action" value="generatepackage">';
4591  print '<input type="hidden" name="tab" value="'.dol_escape_htmltag($tab).'">';
4592  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4593  print '<input type="submit" class="button" name="generatepackage" value="'.$langs->trans("BuildPackage").'">';
4594  print '</form>';
4595  }
4596 
4597  if ($tab == 'tabs') {
4598  $pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
4599 
4600  $tabs = $moduleobj->tabs;
4601 
4602  if ($action != 'editfile' || empty($file)) {
4603  print '<span class="opacitymedium">';
4604  $htmlhelp = $langs->trans("TabsDefDescTooltip", '{s1}');
4605  $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);
4606  print $form->textwithpicto($langs->trans("TabsDefDesc"), $htmlhelp, 1, 'help', '', 0, 2, 'helpondesc').'<br>';
4607  print '</span>';
4608  print '<br>';
4609 
4610  print '<span class="fa fa-file-o"></span> '.$langs->trans("DescriptorFile").' : <strong>'.$pathtofile.'</strong>';
4611  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>';
4612  print '<br>';
4613 
4614  print '<br>';
4615  print load_fiche_titre($langs->trans("ListOfTabsEntries"), '', '');
4616 
4617  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4618  print '<input type="hidden" name="token" value="'.newToken().'">';
4619  print '<input type="hidden" name="action" value="addproperty">';
4620  print '<input type="hidden" name="tab" value="objects">';
4621  print '<input type="hidden" name="module" value="'.dol_escape_htmltag($module).'">';
4622  print '<input type="hidden" name="tabobj" value="'.dol_escape_htmltag($tabobj).'">';
4623 
4624  print '<div class="div-table-responsive">';
4625  print '<table class="noborder small">';
4626 
4627  print '<tr class="liste_titre">';
4628  print_liste_field_titre("ObjectType", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4629  print_liste_field_titre("Tab", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4630  print_liste_field_titre("Title", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4631  print_liste_field_titre("LangFile", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4632  print_liste_field_titre("Condition", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4633  print_liste_field_titre("Path", $_SERVER["PHP_SELF"], '', "", $param, '', $sortfield, $sortorder);
4634  print "</tr>\n";
4635 
4636  if (count($tabs)) {
4637  foreach ($tabs as $tab) {
4638  $parts = explode(':', $tab['data']);
4639 
4640  $objectType = $parts[0];
4641  $tabName = $parts[1];
4642  $tabTitle = isset($parts[2]) ? $parts[2] : '';
4643  $langFile = isset($parts[3]) ? $parts[3] : '';
4644  $condition = isset($parts[4]) ? $parts[4] : '';
4645  $path = isset($parts[5]) ? $parts[5] : '';
4646 
4647  // If we want to remove the tab, then the format is 'objecttype:tabname:optionalcondition'
4648  // See: https://wiki.dolibarr.org/index.php?title=Tabs_system#To_remove_an_existing_tab
4649  if ($tabName[0] === '-') {
4650  $tabTitle = '';
4651  $condition = isset($parts[2]) ? $parts[2] : '';
4652  }
4653 
4654  print '<tr class="oddeven">';
4655 
4656  print '<td>';
4657  print dol_escape_htmltag($parts[0]);
4658  print '</td>';
4659 
4660  print '<td>';
4661  if ($tabName[0] === "+") {
4662  print '<span class="badge badge-status4 badge-status">' . dol_escape_htmltag($tabName) . '</span>';
4663  } else {
4664  print '<span class="badge badge-status8 badge-status">' . dol_escape_htmltag($tabName) . '</span>';
4665  }
4666  print '</td>';
4667 
4668  print '<td>';
4669  print dol_escape_htmltag($tabTitle);
4670  print '</td>';
4671 
4672  print '<td>';
4673  print dol_escape_htmltag($langFile);
4674  print '</td>';
4675 
4676  print '<td>';
4677  print dol_escape_htmltag($condition);
4678  print '</td>';
4679 
4680  print '<td>';
4681  print dol_escape_htmltag($path);
4682  print '</td>';
4683 
4684  print '</tr>';
4685  }
4686  } else {
4687  print '<tr><td class="opacitymedium" colspan="5">'.$langs->trans("None").'</td></tr>';
4688  }
4689 
4690  print '</table>';
4691  print '</div>';
4692 
4693  print '</form>';
4694  } else {
4695  $fullpathoffile = dol_buildpath($file, 0);
4696 
4697  $content = file_get_contents($fullpathoffile);
4698 
4699  // New module
4700  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
4701  print '<input type="hidden" name="token" value="'.newToken().'">';
4702  print '<input type="hidden" name="action" value="savefile">';
4703  print '<input type="hidden" name="file" value="'.dol_escape_htmltag($file).'">';
4704  print '<input type="hidden" name="tab" value="'.$tab.'">';
4705  print '<input type="hidden" name="module" value="'.$module.'">';
4706 
4707  $doleditor = new DolEditor('editfilecontent', $content, '', '300', 'Full', 'In', true, false, 'ace', 0, '99%');
4708  print $doleditor->Create(1, '', false, $langs->trans("File").' : '.$file, (GETPOST('format', 'aZ09') ?GETPOST('format', 'aZ09') : 'html'));
4709  print '<br>';
4710  print '<center>';
4711  print '<input type="submit" class="button buttonforacesave button-save" id="savefile" name="savefile" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
4712  print ' &nbsp; ';
4713  print '<input type="submit" class="button button-cancel" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
4714  print '</center>';
4715 
4716  print '</form>';
4717  }
4718  }
4719 
4720  if ($tab != 'description') {
4721  print dol_get_fiche_end();
4722  }
4723  }
4724 }
4725 
4726 print dol_get_fiche_end(); // End modules
4727 
4728 // End of page
4729 llxFooter();
4730 $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:596
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:1401
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
Copy a file to another file.
Definition: files.lib.php:712
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:1250
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1376
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:480
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:626
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:772
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:450
dol_is_dir_empty($dir)
Return if path is empty.
Definition: files.lib.php:466
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.