dolibarr 21.0.0-alpha
modules_boxes.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2013 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
5 * Copyright (C) 2015 Frederic France <frederic.france@free.fr>
6 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * or see https://www.gnu.org/
21 */
22
35class ModeleBoxes // Can't be abstract as it is instantiated to build "empty" boxes
36{
40 public $db;
41
47 public $version;
48
52 public $param;
53
57 public $info_box_head = array();
58
62 public $info_box_contents = array();
63
67 public $error = '';
68
72 public $max = 5;
73
77 public $enabled = 1;
78
82 public $hidden = false;
83
87 public $rowid;
88
93 public $id;
94
98 public $position;
99
103 public $box_order;
104
108 public $fk_user;
109
113 public $sourcefile;
114
118 public $class;
119
123 public $box_id;
124
128 public $lang;
129
133 public $boxcode;
134
138 public $note;
139
143 public $widgettype = '';
144
145
147
152 public $boximg;
156 public $boxlabel;
160 public $depends;
164 public $urltoaddentry;
168 public $msgNoRecords = 'NoRecordFound';
169
170
171
178 public function __construct($db, $param = '')
179 {
180 $this->db = $db;
181 }
182
183
184
191 public function loadBox($max = 5)
192 {
193 // Must be implemented in derived classes
194 $msg = get_class($this)."::".__FUNCTION__." not implemented";
195 dol_syslog($msg, LOG_ERR);
196 }
197
198
204 public function error()
205 {
206 return $this->error;
207 }
208
209
217 public function fetch($rowid)
218 {
219 global $conf;
220
221 // Recupere liste des boites d'un user si ce dernier a sa propre liste
222 $sql = "SELECT b.rowid as id, b.box_id, b.position, b.box_order, b.fk_user";
223 $sql .= " FROM ".MAIN_DB_PREFIX."boxes as b";
224 $sql .= " WHERE b.entity = ".$conf->entity;
225 $sql .= " AND b.rowid = ".((int) $rowid);
226
227 dol_syslog(get_class($this)."::fetch rowid=".((int) $rowid));
228
229 $resql = $this->db->query($sql);
230 if ($resql) {
231 $obj = $this->db->fetch_object($resql);
232 if ($obj) {
233 $this->id = $obj->id;
234 $this->rowid = $obj->id; // For backward compatibility
235 $this->box_id = $obj->box_id;
236 $this->position = $obj->position;
237 $this->box_order = $obj->box_order;
238 $this->fk_user = $obj->fk_user;
239 return 1;
240 } else {
241 return -1;
242 }
243 } else {
244 return -1;
245 }
246 }
247
256 public function showBox($head = null, $contents = null, $nooutput = 0)
257 {
258 global $langs, $user, $conf;
259
260 if (!empty($this->hidden)) {
261 return "\n<!-- Box ".get_class($this)." hidden -->\n"; // Nothing done if hidden (for example when user has no permission)
262 }
263
264 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
265
266 $MAXLENGTHBOX = 60; // When set to 0: no length limit
267
268 $cachetime = 900; // 900 : 15mn
269 $cachedir = DOL_DATA_ROOT.'/users/temp/widgets';
270 $fileid = get_class($this).'id-'.$this->box_id.'-e'.$conf->entity.'-u'.$user->id.'-s'.$user->socid.'.cache';
271 $filename = '/box-'.$fileid;
272 $refresh = dol_cache_refresh($cachedir, $filename, $cachetime);
273 $out = '';
274
275 if ($contents === null) {
276 $contents = array();
277 }
278
279 if ($refresh) {
280 dol_syslog(get_class($this).'::showBox');
281
282 // Define nbcol and nblines of the box to show
283 $nbcol = 0;
284 if (isset($contents[0])) {
285 $nbcol = count($contents[0]);
286 }
287 $nblines = count($contents);
288
289 $out .= "\n<!-- Box ".get_class($this)." start -->\n";
290
291 $out .= '<div class="box divboxtable boxdraggable" id="boxto_'.$this->box_id.'">'."\n";
292 if (!empty($head['text']) || !empty($head['sublink']) || !empty($head['subpicto']) || $nblines) {
293 $out .= '<table summary="boxtable'.$this->box_id.'" class="noborder boxtable centpercent">'."\n";
294 }
295
296 // Show box title
297 if (!empty($head['text']) || !empty($head['sublink']) || !empty($head['subpicto'])) {
298 $out .= '<tr class="liste_titre box_titre">';
299 $out .= '<th';
300 if (!empty($head['nbcol'])) {
301 $nbcol = $head['nbcol'];
302 }
303 if ($nbcol > 1) {
304 $out .= ' colspan="'.$nbcol.'"';
305 }
306 $out .= '>';
307 if (!empty($conf->use_javascript_ajax)) {
308 //$out.= '<table summary="" class="nobordernopadding" width="100%"><tr><td class="tdoverflowmax150 maxwidth150onsmartphone">';
309 $out .= '<div class="tdoverflowmax400 maxwidth250onsmartphone float">';
310 }
311 if (!empty($head['text']) && !is_array($head['text'])) {
312 $s = dol_trunc($head['text'], isset($head['limit']) ? $head['limit'] : $MAXLENGTHBOX);
313 $out .= $s;
314 }
315 if (!empty($conf->use_javascript_ajax)) {
316 $out .= '</div>';
317 }
318 //$out.= '</td>';
319
320 if (!empty($conf->use_javascript_ajax)) {
321 $sublink = '';
322 if (!empty($head['sublink'])) {
323 $sublink .= '<a href="'.$head['sublink'].'"'.(empty($head['target']) ? '' : ' target="'.$head['target'].'"').'>';
324 }
325 if (!empty($head['subpicto']) && !is_array($head['subtext']) && !is_array($head['subpicto'])) {
326 $sublink .= img_picto($head['subtext'], $head['subpicto'], 'class="opacitymedium marginleftonly '.(empty($head['subclass']) ? '' : $head['subclass']).'" id="idsubimg'.$this->boxcode.'"');
327 }
328 if (!empty($head['sublink'])) {
329 $sublink .= '</a>';
330 }
331
332 //$out.= '<td class="nocellnopadd boxclose right nowraponall">';
333 $out .= '<div class="nocellnopadd boxclose floatright nowraponall">';
334 $out .= $sublink;
335 // The image must have the class 'boxhandle' because it's value used in DOM draggable objects to define the area used to catch the full object
336 $out .= img_picto($langs->trans("MoveBox", $this->box_id), 'grip_title', 'class="opacitymedium boxhandle hideonsmartphone cursormove marginleftonly"');
337 $out .= img_picto($langs->trans("CloseBox", $this->box_id), 'close_title', 'class="opacitymedium boxclose cursorpointer marginleftonly" rel="x:y" id="imgclose'.$this->box_id.'"');
338 $label = $head['text'];
339 //if (!empty($head['graph'])) $label.=' ('.$langs->trans("Graph").')';
340 if (!empty($head['graph'])) {
341 $label .= ' <span class="opacitymedium fas fa-chart-bar"></span>';
342 }
343 $out .= '<input type="hidden" id="boxlabelentry'.$this->box_id.'" value="'.dol_escape_htmltag($label).'">';
344 //$out.= '</td></tr></table>';
345 $out .= '</div>';
346 }
347
348 $out .= "</th>";
349 $out .= "</tr>\n";
350 }
351
352 // Show box lines
353 if ($nblines) {
354 // Loop on each record
355 foreach (array_keys($contents) as $i) {
356 if (isset($contents[$i]) && is_array($contents[$i])) {
357 // TR
358 if (isset($contents[$i][0]['tr'])) {
359 $out .= '<tr '.$contents[$i][0]['tr'].'>';
360 } else {
361 $out .= '<tr class="oddeven">';
362 }
363
364 // Loop on each TD
365 $nbcolthisline = count($contents[$i]);
366 foreach (array_keys($contents[$i]) as $j) {
367 // Define tdparam
368 $tdparam = '';
369 if (!empty($contents[$i][$j]['td'])) {
370 $tdparam .= ' '.$contents[$i][$j]['td'];
371 }
372
373 $text = isset($contents[$i][$j]['text']) ? $contents[$i][$j]['text'] : '';
374 $textwithnotags = preg_replace('/<([^>]+)>/i', '', $text);
375 $text2 = isset($contents[$i][$j]['text2']) ? $contents[$i][$j]['text2'] : '';
376 $text2withnotags = preg_replace('/<([^>]+)>/i', '', $text2);
377
378 $textnoformat = isset($contents[$i][$j]['textnoformat']) ? $contents[$i][$j]['textnoformat'] : '';
379 //$out.= "xxx $textwithnotags y";
380 if (empty($contents[$i][$j]['tooltip'])) {
381 $contents[$i][$j]['tooltip'] = "";
382 }
383 $tooltip = isset($contents[$i][$j]['tooltip']) ? $contents[$i][$j]['tooltip'] : '';
384
385 $out .= '<td'.$tdparam.'>'."\n";
386
387 // Url
388 if (!empty($contents[$i][$j]['url']) && empty($contents[$i][$j]['logo'])) {
389 $out .= '<a href="'.$contents[$i][$j]['url'].'"';
390 if (!empty($tooltip)) {
391 $out .= ' title="'.dol_escape_htmltag($langs->trans("Show").' '.$tooltip, 1).'" class="classfortooltip"';
392 }
393 //$out.= ' alt="'.$textwithnotags.'"'; // Pas de alt sur un "<a href>"
394 $out .= isset($contents[$i][$j]['target']) ? ' target="'.$contents[$i][$j]['target'].'"' : '';
395 $out .= '>';
396 }
397
398 // Logo
399 if (!empty($contents[$i][$j]['logo'])) {
400 $logo = preg_replace("/^object_/i", "", $contents[$i][$j]['logo']);
401 $out .= '<a href="'.$contents[$i][$j]['url'].'">';
402 $out .= img_object($langs->trans("Show").' '.$tooltip, $logo, 'class="classfortooltip"');
403 }
404
405 $maxlength = $MAXLENGTHBOX;
406 if (isset($contents[$i][$j]['maxlength'])) {
407 $maxlength = $contents[$i][$j]['maxlength'];
408 }
409
410 if ($maxlength) {
411 $textwithnotags = dol_trunc($textwithnotags, $maxlength);
412 }
413 if (preg_match('/^<(img|div|span)/i', $text) || !empty($contents[$i][$j]['asis'])) {
414 $out .= $text; // show text with no html cleaning
415 } else {
416 $out .= $textwithnotags; // show text with html cleaning
417 }
418
419 // End Url
420 if (!empty($contents[$i][$j]['url'])) {
421 $out .= '</a>';
422 }
423
424 if (preg_match('/^<(img|div|span)/i', $text2) || !empty($contents[$i][$j]['asis2'])) {
425 $out .= $text2; // show text with no html cleaning
426 } else {
427 $out .= $text2withnotags; // show text with html cleaning
428 }
429
430 if (!empty($textnoformat)) {
431 $out .= "\n".$textnoformat."\n";
432 }
433
434 $out .= "</td>\n";
435 }
436
437 $out .= "</tr>\n";
438 }
439 }
440 } else {
441 if (!empty($head['text']) || !empty($head['sublink']) || !empty($head['subpicto']) || $nblines) {
442 $out .= '<tr><td colspan="2" class="center"><span class="opacitymedium">'.$langs->trans($this->msgNoRecords).' </span>';
443
444 // Check if $urltoaddentry is defined for the widget
445 if (!empty($this->urltoaddentry)) {
446 $out .= '<a href="'.$this->urltoaddentry.'">'.img_picto($langs->trans("New"), 'add', 'pictofixedwidth').'</a>';
447 }
448
449 $out .= '</td></tr>';
450 }
451 }
452
453 if (!empty($head['text']) || !empty($head['sublink']) || !empty($head['subpicto']) || $nblines) {
454 $out .= "</table>\n";
455 }
456
457 // If invisible box with no contents
458 if (empty($head['text']) && empty($head['sublink']) && empty($head['subpicto']) && !$nblines) {
459 $out .= "<br>\n";
460 }
461
462 $out .= "</div>\n";
463
464 $out .= "<!-- Box ".get_class($this)." end -->\n\n";
465 if (getDolGlobalString('MAIN_ACTIVATE_FILECACHE')) {
466 dol_filecache($cachedir, $filename, $out);
467 }
468 } else {
469 dol_syslog(get_class($this).'::showBoxCached');
470 $out = "<!-- Box ".get_class($this)." from cache -->";
471 $out .= dol_readcachefile($cachedir, $filename);
472 }
473
474 if ($nooutput) {
475 return $out;
476 } else {
477 print $out;
478 }
479
480 return '';
481 }
482
483
492 public static function getWidgetsList($forcedirwidget = null)
493 {
494 global $langs, $db;
495
496 $files = array();
497 $fullpath = array();
498 $relpath = array();
499 $iscoreorexternal = array();
500 $modules = array();
501 $orders = array();
502 $i = 0;
503
504 //$dirwidget=array_merge(array('/core/boxes/'), $conf->modules_parts['widgets']);
505 $dirwidget = array('/core/boxes/'); // $conf->modules_parts['widgets'] is not required
506 if (is_array($forcedirwidget)) {
507 $dirwidget = $forcedirwidget;
508 }
509
510 foreach ($dirwidget as $reldir) {
511 $dir = dol_buildpath($reldir, 0);
512 $newdir = dol_osencode($dir);
513
514 // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
515 if (!is_dir($newdir)) {
516 continue;
517 }
518
519 $handle = opendir($newdir);
520 if (is_resource($handle)) {
521 while (($file = readdir($handle)) !== false) {
522 $reg = array();
523 if (is_readable($newdir.'/'.$file) && preg_match('/^(.+)\.php/', $file, $reg)) {
524 if (preg_match('/\.back$/', $file) || preg_match('/^(.+)\.disabled\.php/', $file)) {
525 continue;
526 }
527
528 $part1 = $reg[1];
529
530 $modName = ucfirst($reg[1]);
531 //print "file=$file"; print "modName=$modName"; exit;
532 if (in_array($modName, $modules)) {
533 $langs->load("errors");
534 print '<div class="error">'.$langs->trans("Error").' : '.$langs->trans("ErrorDuplicateWidget", $modName, "").'</div>';
535 } else {
536 try {
537 include_once $newdir.'/'.$file;
538 } catch (Exception $e) {
539 print $e->getMessage();
540 }
541 }
542
543 $files[$i] = $file;
544 $fullpath[$i] = $dir.'/'.$file;
545 $relpath[$i] = preg_replace('/^\//', '', $reldir).'/'.$file;
546 $iscoreorexternal[$i] = ($reldir == '/core/boxes/' ? 'internal' : 'external');
547 $modules[$i] = $modName;
548 $orders[$i] = $part1; // Set sort criteria value
549
550 $i++;
551 }
552 }
553 closedir($handle);
554 }
555 }
556 //echo "<pre>";print_r($modules);echo "</pre>";
557
558 asort($orders);
559
560 $widget = array();
561 $j = 0;
562
563 // Loop on each widget
564 foreach ($orders as $key => $value) {
565 $modName = $modules[$key];
566 if (empty($modName)) {
567 continue;
568 }
569
570 if (!class_exists($modName)) {
571 print 'Error: A widget file was found but its class "'.$modName.'" was not found.'."<br>\n";
572 continue;
573 }
574
575 $objMod = new $modName($db);
576 '@phan-var-force ModeleBoxes $objMod';
577 if (is_object($objMod)) {
578 // Define disabledbyname and disabledbymodule
579 $disabledbyname = 0;
580 $disabledbymodule = 0; // TODO Set to 2 if module is not enabled
581 $module = '';
582
583 // Check if widget file is disabled by name
584 if (preg_match('/NORUN$/i', $files[$key])) {
585 $disabledbyname = 1;
586 }
587
588 // We set info of modules @phan-suppress-next-line PhanUndeclaredProperty
589 $widget[$j]['picto'] = ((!property_exists($objMod, 'picto') || empty($objMod->picto)) ? (empty($objMod->boximg) ? img_object('', 'generic') : $objMod->boximg) : img_object('', $objMod->picto));
590 $widget[$j]['file'] = $files[$key];
591 $widget[$j]['fullpath'] = $fullpath[$key];
592 $widget[$j]['relpath'] = $relpath[$key];
593 $widget[$j]['iscoreorexternal'] = $iscoreorexternal[$key];
594 $widget[$j]['version'] = empty($objMod->version) ? '' : $objMod->version;
595 $widget[$j]['status'] = img_picto($langs->trans("Active"), 'tick');
596 if ($disabledbyname > 0 || $disabledbymodule > 1) {
597 $widget[$j]['status'] = '';
598 }
599
600 $text = '<b>'.$langs->trans("Description").':</b><br>';
601 $text .= $objMod->boxlabel.'<br>';
602 $text .= '<br><b>'.$langs->trans("Status").':</b><br>';
603 if ($disabledbymodule == 2) {
604 $text .= $langs->trans("WidgetDisabledAsModuleDisabled", $module).'<br>';
605 }
606
607 $widget[$j]['info'] = $text;
608 }
609 $j++;
610 }
611
612 return $widget;
613 }
614}
print $object position
Definition edit.php:195
Class ModeleBoxes.
showBox($head=null, $contents=null, $nooutput=0)
Standard method to show a box (usage by boxes not mandatory, a box can still use its own showBox func...
fetch($rowid)
Load a box line from its rowid.
error()
Return last error message.
__construct($db, $param='')
Constructor.
loadBox($max=5)
Load data for box to show them later.
static getWidgetsList($forcedirwidget=null)
Return list of widget.
dol_filecache($directory, $filename, $object)
Store object in file.
dol_readcachefile($directory, $filename)
Read object from cachefile.
dol_cache_refresh($directory, $filename, $cachetime)
Test if Refresh needed.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
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.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...