dolibarr  9.0.0
modulehelp.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2017 Regis Houssin <regis.houssin@inodbox.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 <http://www.gnu.org/licenses/>.
17  */
18 
24 if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); // If there is no need to load and show top and left menu
25 
26 require '../main.inc.php';
27 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
30 
31 // Load translation files required by the page
32 $langs->loadLangs(array('errors', 'admin'));
33 
34 $mode=GETPOST('mode', 'alpha');
35 $action=GETPOST('action','alpha');
36 $id = GETPOST('id', 'int');
37 if (empty($mode)) $mode='desc';
38 
39 if (! $user->admin)
41 
42 
43 
44 /*
45  * Actions
46  */
47 
48 // Nothing
49 
50 
51 /*
52  * View
53  */
54 
55 $form = new Form($db);
56 
57 $help_url='EN:First_setup|FR:Premiers_param├ętrages|ES:Primeras_configuraciones';
58 llxHeader('',$langs->trans("Setup"),$help_url);
59 
60 print '<!-- Force style container -->'."\n".'<style>
61 .id-container {
62  width: 100%;
63 }
64 </style>';
65 
66 $arrayofnatures=array('core'=>$langs->transnoentitiesnoconv("Core"), 'external'=>$langs->transnoentitiesnoconv("External").' - '.$langs->trans("AllPublishers"));
67 
68 // Search modules dirs
69 $modulesdir = dolGetModulesDirs();
70 
71 
72 $filename = array();
73 $modules = array();
74 $orders = array();
75 $categ = array();
76 $dirmod = array();
77 $i = 0; // is a sequencer of modules found
78 $j = 0; // j is module number. Automatically affected if module number not defined.
79 $modNameLoaded=array();
80 
81 foreach ($modulesdir as $dir)
82 {
83  // Load modules attributes in arrays (name, numero, orders) from dir directory
84  //print $dir."\n<br>";
85  dol_syslog("Scan directory ".$dir." for module descriptor files (modXXX.class.php)");
86  $handle=@opendir($dir);
87  if (is_resource($handle))
88  {
89  while (($file = readdir($handle))!==false)
90  {
91  //print "$i ".$file."\n<br>";
92  if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php')
93  {
94  $modName = substr($file, 0, dol_strlen($file) - 10);
95 
96  if ($modName)
97  {
98  if (! empty($modNameLoaded[$modName]))
99  {
100  $mesg="Error: Module ".$modName." was found twice: Into ".$modNameLoaded[$modName]." and ".$dir.". You probably have an old file on your disk.<br>";
101  setEventMessages($mesg, null, 'warnings');
102  dol_syslog($mesg, LOG_ERR);
103  continue;
104  }
105 
106  try
107  {
108  $res=include_once $dir.$file;
109  if (class_exists($modName))
110  {
111  try {
112  $objMod = new $modName($db);
113  $modNameLoaded[$modName]=$dir;
114 
115  if (! $objMod->numero > 0 && $modName != 'modUser')
116  {
117  dol_syslog('The module descriptor '.$modName.' must have a numero property', LOG_ERR);
118  }
119  $j = $objMod->numero;
120 
121  $modulequalified=1;
122 
123  // We discard modules according to features level (PS: if module is activated we always show it)
124  $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i','',get_class($objMod)));
125  if ($objMod->version == 'development' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 2))) $modulequalified=0;
126  if ($objMod->version == 'experimental' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 1))) $modulequalified=0;
127  if (preg_match('/deprecated/', $objMod->version) && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL >= 0))) $modulequalified=0;
128 
129  // We discard modules according to property disabled
130  if (! empty($objMod->hidden)) $modulequalified=0;
131 
132  if ($modulequalified > 0)
133  {
134  $publisher=dol_escape_htmltag($objMod->getPublisher());
135  $external=($objMod->isCoreOrExternalModule() == 'external');
136  if ($external)
137  {
138  if ($publisher)
139  {
140  $arrayofnatures['external_'.$publisher]=$langs->trans("External").' - '.$publisher;
141  }
142  else
143  {
144  $arrayofnatures['external_']=$langs->trans("External").' - '.$langs->trans("UnknownPublishers");
145  }
146  }
147  ksort($arrayofnatures);
148  }
149 
150  // Define array $categ with categ with at least one qualified module
151  if ($modulequalified > 0)
152  {
153  $modules[$i] = $objMod;
154  $filename[$i]= $modName;
155 
156  // Gives the possibility to the module, to provide his own family info and position of this family
157  if (is_array($objMod->familyinfo) && !empty($objMod->familyinfo)) {
158  if (!is_array($familyinfo)) $familyinfo=array();
159  $familyinfo = array_merge($familyinfo, $objMod->familyinfo);
160  $familykey = key($objMod->familyinfo);
161  } else {
162  $familykey = $objMod->family;
163  }
164 
165  $moduleposition = ($objMod->module_position?$objMod->module_position:'50');
166  if ($moduleposition == '50' && ($objMod->isCoreOrExternalModule() == 'external'))
167  {
168  $moduleposition = '80'; // External modules at end by default
169  }
170 
171  $orders[$i] = $familyinfo[$familykey]['position']."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number
172  $dirmod[$i] = $dir;
173  //print $i.'-'.$dirmod[$i].'<br>';
174  // Set categ[$i]
175  $specialstring = 'unknown';
176  if ($objMod->version == 'development' || $objMod->version == 'experimental') $specialstring='expdev';
177  if (isset($categ[$specialstring])) $categ[$specialstring]++; // Array of all different modules categories
178  else $categ[$specialstring]=1;
179  $j++;
180  $i++;
181  }
182  else dol_syslog("Module ".get_class($objMod)." not qualified");
183  }
184  catch(Exception $e)
185  {
186  dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR);
187  }
188  }
189  else
190  {
191  print "Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)<br>";
192  }
193  }
194  catch(Exception $e)
195  {
196  dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR);
197  }
198  }
199  }
200  }
201  closedir($handle);
202  }
203  else
204  {
205  dol_syslog("htdocs/admin/modulehelp.php: Failed to open directory ".$dir.". See permission and open_basedir option.", LOG_WARNING);
206  }
207 }
208 
209 asort($orders);
210 //var_dump($orders);
211 //var_dump($categ);
212 //var_dump($modules);
213 
214 
215 $i=0;
216 foreach($orders as $tmpkey => $tmpvalue)
217 {
218  $objMod = $modules[$tmpkey];
219  if ($objMod->numero == $id)
220  {
221  $key = $i;
222  $modName = $filename[$tmpkey];
223  $dirofmodule = $dirmod[$tmpkey];
224  break;
225  }
226  $i++;
227 }
228 $value = $orders[$key];
229 $tab=explode('_',$value);
230 $familyposition=$tab[0]; $familykey=$tab[1]; $module_position=$tab[2]; $numero=$tab[3];
231 
232 
233 
234 $h = 0;
235 
236 $head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=desc';
237 $head[$h][1] = $langs->trans("Description");
238 $head[$h][2] = 'desc';
239 $h++;
240 
241 $head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=feature';
242 $head[$h][1] = $langs->trans("TechnicalServicesProvided");
243 $head[$h][2] = 'feature';
244 $h++;
245 
246 if ($objMod->isCoreOrExternalModule() == 'external')
247 {
248  $head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=changelog';
249  $head[$h][1] = $langs->trans("ChangeLog");
250  $head[$h][2] = 'changelog';
251  $h++;
252 }
253 
254 // Check filters
255 $modulename=$objMod->getName();
256 $moduledesc=$objMod->getDesc();
257 $moduleauthor=$objMod->getPublisher();
258 $moduledir=strtolower(preg_replace('/^mod/i','',get_class($objMod)));
259 
260 
261 print '<div class="centpercent">';
262 
263 print load_fiche_titre(($modulename?$modulename:$moduledesc), $moreinfo, 'object_'.$objMod->picto);
264 print '<br>';
265 
266 dol_fiche_head($head, $mode, $title, -1);
267 
268 if (! $modulename)
269 {
270  dol_syslog("Error for module ".$key." - Property name of module looks empty", LOG_WARNING);
271 }
272 
273 $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i','',get_class($objMod)));
274 
275 // Load all lang files of module
276 if (isset($objMod->langfiles) && is_array($objMod->langfiles))
277 {
278  foreach($objMod->langfiles as $domain)
279  {
280  $langs->load($domain);
281  }
282 }
283 
284 
285 
286 
287 // Version (with picto warning or not)
288 $version=$objMod->getVersion(0);
289 $versiontrans='';
290 if (preg_match('/development/i', $version)) $versiontrans.=img_warning($langs->trans("Development"), 'style="float: left"');
291 if (preg_match('/experimental/i', $version)) $versiontrans.=img_warning($langs->trans("Experimental"), 'style="float: left"');
292 if (preg_match('/deprecated/i', $version)) $versiontrans.=img_warning($langs->trans("Deprecated"), 'style="float: left"');
293 $versiontrans.=$objMod->getVersion(1);
294 
295 // Define imginfo
296 $imginfo="info";
297 if ($objMod->isCoreOrExternalModule() == 'external')
298 {
299  $imginfo="info_black";
300 }
301 
302 // Define text of description of module
303 $text='';
304 
305 if ($mode == 'desc')
306 {
307  if ($moduledesc) $text.=$moduledesc.'<br><br>';
308 
309  $text.='<strong>'.$langs->trans("Version").':</strong> '.$version;
310 
311  $textexternal='';
312  if ($objMod->isCoreOrExternalModule() == 'external')
313  {
314  $textexternal.='<br><strong>'.$langs->trans("Origin").':</strong> '.$langs->trans("ExternalModule",$dirofmodule);
315  if ($objMod->editor_name != 'dolibarr') $textexternal.='<br><strong>'.$langs->trans("Publisher").':</strong> '.(empty($objMod->editor_name)?$langs->trans("Unknown"):$objMod->editor_name);
316  $editor_url = $objMod->editor_url;
317  if (! preg_match('/^http/', $editor_url)) $editor_url = 'http://'.$editor_url;
318  if (! empty($objMod->editor_url) && ! preg_match('/dolibarr\.org/i',$objMod->editor_url)) $textexternal.='<br><strong>'.$langs->trans("Url").':</strong> <a href="'.$editor_url.'" target="_blank">'.$objMod->editor_url.'</a>';
319  $text.=$textexternal;
320  $text.='<br>';
321  }
322  else
323  {
324  $text.='<br><strong>'.$langs->trans("Origin").':</strong> '.$langs->trans("Core").'<br>';
325  }
326  $text.='<br><strong>'.$langs->trans("LastActivationDate").':</strong> ';
327  if (! empty($conf->global->$const_name)) $text.=dol_print_date($objMod->getLastActivationDate(), 'dayhour');
328  else $text.=$langs->trans("Disabled");
329  $text.='<br>';
330 
331  $tmp = $objMod->getLastActivationInfo();
332  $authorid = $tmp['authorid'];
333  if ($authorid > 0)
334  {
335  $tmpuser = new User($db);
336  $tmpuser->fetch($authorid);
337  $text.='<strong>'.$langs->trans("LastActivationAuthor").':</strong> ';
338  $text.= $tmpuser->getNomUrl(1);
339  $text.='<br>';
340  }
341  $ip = $tmp['ip'];
342  if ($ip)
343  {
344  $text.='<strong>'.$langs->trans("LastActivationIP").':</strong> ';
345  $text.= $ip;
346  $text.='<br>';
347  }
348 
349  $moduledesclong=$objMod->getDescLong();
350  if ($moduledesclong) $text.='<br><hr><div class="moduledesclong">'.$moduledesclong.'<div>';
351 }
352 
353 if ($mode == 'feature')
354 {
355  $text.='<br><strong>'.$langs->trans("DependsOn").':</strong> ';
356  if (count($objMod->depends)) $text.=join(',', $objMod->depends);
357  else $text.=$langs->trans("None");
358  $text.='<br><strong>'.$langs->trans("RequiredBy").':</strong> ';
359  if (count($objMod->requiredby)) $text.=join(',', $objMod->requiredby);
360  else $text.=$langs->trans("None");
361 
362  $text.='<br><br>';
363 
364  $text.='<br><strong>'.$langs->trans("AddDataTables").':</strong> ';
365  $sqlfiles = dol_dir_list(dol_buildpath($moduledir.'/sql/'), 'files', 0, 'llx.*\.sql', array('\.key\.sql'));
366  if (count($sqlfiles) > 0)
367  {
368  $text.=$langs->trans("Yes").' (';
369  $i=0;
370  foreach($sqlfiles as $val)
371  {
372  $text.=($i?', ':'').preg_replace('/\.sql$/','',preg_replace('/llx_/','',$val['name']));
373  $i++;
374  }
375  $text.=')';
376  }
377  else $text.=$langs->trans("No");
378 
379  $text.='<br>';
380 
381  $text.='<br><strong>'.$langs->trans("AddDictionaries").':</strong> ';
382  if (isset($objMod->dictionaries) && isset($objMod->dictionaries['tablib']) && is_array($objMod->dictionaries['tablib']) && count($objMod->dictionaries['tablib']))
383  {
384  $i=0;
385  foreach($objMod->dictionaries['tablib'] as $val)
386  {
387  $text.=($i?', ':'').$val;
388  $i++;
389  }
390  }
391  else $text.=$langs->trans("No");
392 
393  $text.='<br>';
394 
395  $text.='<br><strong>'.$langs->trans("AddData").':</strong> ';
396  $filedata = dol_buildpath($moduledir.'/sql/data.sql');
397  if (dol_is_file($filedata))
398  {
399  $text.=$langs->trans("Yes").' ('.$moduledir.'/sql/data.sql'.')';
400  }
401  else $text.=$langs->trans("No");
402 
403  $text.='<br>';
404 
405  $text.='<br><strong>'.$langs->trans("AddRemoveTabs").':</strong> ';
406  if (isset($objMod->tabs) && is_array($objMod->tabs) && count($objMod->tabs))
407  {
408  $i=0;
409  foreach($objMod->tabs as $val)
410  {
411  if (is_array($val)) $val=$val['data'];
412  if (is_string($val))
413  {
414  $tmp=explode(':',$val,3);
415  $text.=($i?', ':'').$tmp[0].':'.$tmp[1];
416  $i++;
417  }
418  }
419  }
420  else $text.=$langs->trans("No");
421 
422  $text.='<br>';
423 
424  $text.='<br><strong>'.$langs->trans("AddModels").':</strong> ';
425  if (isset($objMod->module_parts) && isset($objMod->module_parts['models']) && $objMod->module_parts['models'])
426  {
427  $text.=$langs->trans("Yes");
428  }
429  else $text.=$langs->trans("No");
430 
431  $text.='<br>';
432 
433  $text.='<br><strong>'.$langs->trans("AddSubstitutions").':</strong> ';
434  if (isset($objMod->module_parts) && isset($objMod->module_parts['substitutions']) && $objMod->module_parts['substitutions'])
435  {
436  $text.=$langs->trans("Yes");
437  }
438  else $text.=$langs->trans("No");
439 
440  $text.='<br>';
441 
442  $text.='<br><strong>'.$langs->trans("AddSheduledJobs").':</strong> ';
443  if (isset($objMod->cronjobs) && is_array($objMod->cronjobs) && count($objMod->cronjobs))
444  {
445  $i=0;
446  foreach($objMod->cronjobs as $val)
447  {
448  $text.=($i?', ':'').($val['label']);
449  $i++;
450  }
451  }
452  else $text.=$langs->trans("No");
453 
454  $text.='<br>';
455 
456  $text.='<br><strong>'.$langs->trans("AddTriggers").':</strong> ';
457  $moreinfoontriggerfile='';
458  if (isset($objMod->module_parts) && isset($objMod->module_parts['triggers']) && $objMod->module_parts['triggers'])
459  {
460  $yesno='Yes';
461  }
462  else
463  {
464  $yesno='No';
465  }
466  require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
467  $interfaces = new Interfaces($db);
468  $triggers = $interfaces->getTriggersList(array((($objMod->isCoreOrExternalModule() == 'external')?'/'.$moduledir:'').'/core/triggers'));
469  foreach($triggers as $triggercursor)
470  {
471  if ($triggercursor['module'] == $moduledir)
472  {
473  $yesno='Yes';
474  $moreinfoontriggerfile=' ('.$triggercursor['relpath'].')';
475  }
476  }
477 
478  $text.=$langs->trans($yesno).$moreinfoontriggerfile;
479 
480  $text.='<br>';
481 
482  $text.='<br><strong>'.$langs->trans("AddBoxes").':</strong> ';
483  if (isset($objMod->boxes) && is_array($objMod->boxes) && count($objMod->boxes))
484  {
485  $i=0;
486  foreach($objMod->boxes as $val)
487  {
488  $text.=($i?', ':'').($val['file']?$val['file']:$val[0]);
489  $i++;
490  }
491  }
492  else $text.=$langs->trans("No");
493 
494  $text.='<br>';
495 
496  $text.='<br><strong>'.$langs->trans("AddHooks").':</strong> ';
497  if (isset($objMod->module_parts) && is_array($objMod->module_parts['hooks']) && count($objMod->module_parts['hooks']))
498  {
499  $i=0;
500  foreach($objMod->module_parts['hooks'] as $key => $val)
501  {
502  if ($key === 'entity') continue;
503 
504  // For special values
505  if ($key === 'data')
506  {
507  if (is_array($val))
508  {
509  foreach($val as $value)
510  {
511  $text.=($i?', ':'').($value);
512  $i++;
513  }
514 
515  continue;
516  }
517  }
518 
519  $text.=($i?', ':'').($val);
520  $i++;
521  }
522  }
523  else $text.=$langs->trans("No");
524 
525  $text.='<br>';
526 
527  $text.='<br><strong>'.$langs->trans("AddPermissions").':</strong> ';
528  if (isset($objMod->rights) && is_array($objMod->rights) && count($objMod->rights))
529  {
530  $i=0;
531  foreach($objMod->rights as $val)
532  {
533  $text.=($i?', ':'').($val[1]);
534  $i++;
535  }
536  }
537  else $text.=$langs->trans("No");
538 
539  $text.='<br>';
540 
541  $text.='<br><strong>'.$langs->trans("AddMenus").':</strong> ';
542  if (isset($objMod->menu) && ! empty($objMod->menu)) // objMod can be an array or just an int 1
543  {
544  $text.=$langs->trans("Yes");
545  }
546  else $text.=$langs->trans("No");
547 
548  $text.='<br>';
549 
550  $text.='<br><strong>'.$langs->trans("AddExportProfiles").':</strong> ';
551  if (isset($objMod->export_label) && is_array($objMod->export_label) && count($objMod->export_label))
552  {
553  $i=0;
554  foreach($objMod->export_label as $val)
555  {
556  $text.=($i?', ':'').($val);
557  $i++;
558  }
559  }
560  else $text.=$langs->trans("No");
561 
562  $text.='<br>';
563 
564  $text.='<br><strong>'.$langs->trans("AddImportProfiles").':</strong> ';
565  if (isset($objMod->import_label) && is_array($objMod->import_label) && count($objMod->import_label))
566  {
567  $i=0;
568  foreach($objMod->import_label as $val)
569  {
570  $text.=($i?', ':'').($val);
571  $i++;
572  }
573  }
574  else $text.=$langs->trans("No");
575 
576  $text.='<br>';
577 
578  $text.='<br><strong>'.$langs->trans("AddOtherPagesOrServices").':</strong> ';
579  $text.=$langs->trans("DetectionNotPossible");
580 }
581 
582 
583 if ($mode == 'changelog')
584 {
585  $changelog=$objMod->getChangeLog();
586  if ($changelog) $text.='<div class="moduledesclong">'.$changelog.'<div>';
587  else $text.='<div class="moduledesclong">'.$langs->trans("NotAvailable").'</div>';
588 }
589 
590 print $text;
591 
592 
593 dol_fiche_end();
594 
595 print '</div>';
596 
597 // End of page
598 llxFooter();
599 $db->close();
img_warning($titlealt='default', $moreatt='')
Show warning logo.
llxFooter()
Empty footer.
Definition: wrapper.php:56
load_fiche_titre($titre, $morehtmlright='', $picto='title_generic.png', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print
Draft customers invoices.
Definition: index.php:91
setEventMessages($mesg, $mesgs, $style='mesgs')
Set event messages in dol_events session object.
Class to manage Dolibarr users.
Definition: user.class.php:41
dolGetModulesDirs($subdir='')
Return list of modules directories.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
Class to manage generation of HTML components Only common components must be here.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
dol_fiche_end($notab=0)
Show tab footer of a card.
llxHeader()
Empty header.
Definition: wrapper.php:44
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:59
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:451
dol_print_date($time, $format='', $tzoutput='tzserver', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='')
Show tab header of a card.
Class to manage triggers.