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