dolibarr 24.0.0-beta
customreports.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2020-2024 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
48'
49@phan-var-force ?int[] $toselect
50';
51
52// Initialise values
53$tabfamily = null;
54$objecttype = null;
55
56if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
57 require '../main.inc.php';
58
59 // Get parameters
60 $action = GETPOST('action', 'aZ09') ? GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ...
61 $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
62
63 $mode = GETPOST('mode', 'alpha');
64 $objecttype = (string) GETPOST('objecttype', 'aZ09arobase');
65 $tabfamily = GETPOST('tabfamily', 'aZ09');
66
67 $search_measures = GETPOST('search_measures', 'array:alphanohtml');
68
69 if (GETPOST('search_xaxis', 'alpha') && GETPOST('search_xaxis', 'alpha') != '-1') {
70 $search_xaxis = array(GETPOST('search_xaxis', 'alpha'));
71 } else {
72 $search_xaxis = array();
73 }
74 if (GETPOST('search_groupby', 'alpha') && GETPOST('search_groupby', 'alpha') != '-1') {
75 $search_groupby = array(GETPOST('search_groupby', 'alpha'));
76 } else {
77 $search_groupby = array();
78 }
79 '@phan-var-force string[] $search_groupby';
80
81 $search_yaxis = GETPOST('search_yaxis', 'array:alphanohtml');
82 $search_graph = (string) GETPOST('search_graph', 'restricthtml');
83
90 function sanititzekey($value)
91 {
92 return preg_replace('/[^a-z0-9\._\-]+/', '', $value);
93 }
94
95 $search_measures = array_map('sanititzekey', $search_measures);
96 $search_xaxis = array_map('sanititzekey', $search_xaxis);
97 $search_yaxis = array_map('sanititzekey', $search_yaxis);
98 $search_groupby = array_map('sanititzekey', $search_groupby);
99
100 // Load variable for pagination
101 $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
102 $sortfield = GETPOST('sortfield', 'aZ09comma');
103 $sortorder = GETPOST('sortorder', 'aZ09comma');
104 $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
105 if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
106 $page = 0;
107 } // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
108 $offset = $limit * $page;
109 $pageprev = $page - 1;
110 $pagenext = $page + 1;
111
112 $object = null;
113} else {
114 // When included into a main page
124 '
125 @phan-var-force int<0,1> $SHOWLEGEND
126 @phan-var-force string $customreportkey
127 @phan-var-force ?string $customsql
128 @phan-var-force ?string[] $search_groupby Array with the third dimension
129 @phan-var-force int $page
130 @phan-var-force string $sortfield
131 @phan-var-force string $sortorder
132 ';
133
134 // $search_measures, $search_xaxis or $search_yaxis may have been defined by the parent.
135
136 if (empty($user) || empty($user->id)) {
137 print 'Page is called as an include but $user and its permission loaded with loadRights() are not defined. We stop here.';
138 exit(1);
139 }
140 if (empty($object)) {
141 print 'Page is called as an include but $object is not defined. We stop here.';
142 exit(1);
143 }
144}
145
146// In customreport context, we force the protection to avoid forging of criteria including bind SQL injection
147global $dolibarr_allow_unsecured_select_in_extrafields_filter;
148$dolibarr_allow_unsecured_select_in_extrafields_filter = 0;
149
150if (empty($mode)) {
151 $mode = 'graph';
152}
153if (!isset($search_measures)) {
154 $search_measures = array(0 => 't.count');
155}
156if (!isset($search_xaxis)) {
157 // Ensure value is set and not null.
158 $search_xaxis = array();
159}
160if (!isset($search_yaxis)) {
161 // Ensure value is set and not null.
162 $search_yaxis = array();
163}
164if (!isset($search_groupby)) {
165 // Ensure value is set and not null.
166 $search_groupby = array();
167}
168if (!isset($search_graph)) {
169 // Ensure value is set and not null
170 $search_graph = '';
171}
172if (!empty($object)) {
173 $objecttype = $object->element.($object->module ? '@'.$object->module : '');
174}
175if ((!is_string($objecttype) || empty($objecttype)) && isModEnabled('societe')) {
176 $objecttype = 'thirdparty';
177}
178'@phan-var-force string $objecttype'; // Help phan that suggests $objecttype can be null
179
180require_once DOL_DOCUMENT_ROOT."/core/class/extrafields.class.php";
181require_once DOL_DOCUMENT_ROOT."/core/class/html.form.class.php";
182require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
183require_once DOL_DOCUMENT_ROOT."/core/lib/company.lib.php";
184require_once DOL_DOCUMENT_ROOT."/core/lib/date.lib.php";
185require_once DOL_DOCUMENT_ROOT."/core/lib/customreports.lib.php";
186require_once DOL_DOCUMENT_ROOT."/core/class/dolgraph.class.php";
187require_once DOL_DOCUMENT_ROOT."/core/class/doleditor.class.php";
188require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
189
190// Load traductions files requiredby by page
191$langs->loadLangs(array("companies", "other", "exports", "sendings"));
192
193$extrafields = new ExtraFields($db);
194
195$hookmanager->initHooks(array('customreport')); // Note that conf->hooks_modules contains array
196
197$title = '';
198$picto = '';
199$errormessage = null;
200$keyforlabeloffield = null;
201$head = array();
202$ObjectClassName = '';
203// Objects available by default
204$arrayoftype = array(
205 'thirdparty' => array('label' => 'ThirdParties', 'picto' => 'company', 'ObjectClassName' => 'Societe', 'enabled' => isModEnabled('societe'), 'ClassPath' => "/societe/class/societe.class.php", 'langs' => 'companies'),
206 'contact' => array('label' => 'Contacts', 'picto' => 'contact', 'ObjectClassName' => 'Contact', 'enabled' => isModEnabled('societe'), 'ClassPath' => "/contact/class/contact.class.php"),
207 'proposal' => array('label' => 'Proposals', 'picto' => 'proposal', 'ObjectClassName' => 'Propal', 'enabled' => isModEnabled('propal'), 'ClassPath' => "/comm/propal/class/propal.class.php", 'langs' => 'propal'),
208 'proposaldet' => array('label' => 'ProposalLines', 'picto' => 'proposal', 'ObjectClassName' => 'PropaleLigne', 'enabled' => isModEnabled('propal'), 'ClassPath' => "/comm/propal/class/propaleligne.class.php", 'langs' => 'propal'),
209 'order' => array('label' => 'Orders', 'picto' => 'order', 'ObjectClassName' => 'Commande', 'enabled' => isModEnabled('order'), 'ClassPath' => "/commande/class/commande.class.php", 'langs' => 'orders'),
210 'orderdet' => array('label' => 'SaleOrderLines', 'picto' => 'order', 'ObjectClassName' => 'OrderLine', 'enabled' => isModEnabled('order'), 'ClassPath' => "/commande/class/orderline.class.php", 'langs' => 'orders'),
211 'invoice' => array('label' => 'Invoices', 'picto' => 'bill', 'ObjectClassName' => 'Facture', 'enabled' => isModEnabled('invoice'), 'ClassPath' => "/compta/facture/class/facture.class.php", 'langs' => 'bills'),
212 'invoice_template' => array('label' => 'PredefinedInvoices', 'picto' => 'bill', 'ObjectClassName' => 'FactureRec', 'enabled' => isModEnabled('invoice'), 'ClassPath' => "/compta/facture/class/facture-rec.class.php", 'langs' => 'bills'),
213 'contract' => array('label' => 'Contracts', 'picto' => 'contract', 'ObjectClassName' => 'Contrat', 'enabled' => isModEnabled('contract'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs' => 'contracts'),
214 'contractdet' => array('label' => 'ContractLines', 'picto' => 'contract', 'ObjectClassName' => 'ContratLigne', 'enabled' => isModEnabled('contract'), 'ClassPath' => "/contrat/class/contrat.class.php", 'langs' => 'contracts'),
215 'bom' => array('label' => 'BOM', 'picto' => 'bom', 'ObjectClassName' => 'Bom', 'enabled' => isModEnabled('bom')),
216 'mrp' => array('label' => 'MO', 'picto' => 'mrp', 'ObjectClassName' => 'Mo', 'enabled' => isModEnabled('mrp'), 'ClassPath' => "/mrp/class/mo.class.php"),
217 'ticket' => array('label' => 'Ticket', 'picto' => 'ticket', 'ObjectClassName' => 'Ticket', 'enabled' => isModEnabled('ticket')),
218 'member' => array('langs' => 'members', 'label' => 'Adherent', 'picto' => 'member', 'ObjectClassName' => 'Adherent', 'enabled' => isModEnabled('member'), 'ClassPath' => "/adherents/class/adherent.class.php"),
219 'cotisation' => array('langs' => 'members', 'label' => 'Subscriptions', 'picto' => 'member', 'ObjectClassName' => 'Subscription', 'enabled' => isModEnabled('member'), 'ClassPath' => "/adherents/class/subscription.class.php"),
220);
221
222
223// Complete $arrayoftype by external modules
224$parameters = array('objecttype' => $objecttype, 'tabfamily' => $tabfamily);
225// @phan-suppress-next-line PhanTypeMismatchArgumentNullable
226$reshook = $hookmanager->executeHooks('loadDataForCustomReports', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
227if ($reshook < 0) {
228 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
229} elseif (is_array($hookmanager->resArray)) {
230 if (!empty($hookmanager->resArray['title'])) { // Add entries for tabs
231 $title = $hookmanager->resArray['title'];
232 }
233 if (!empty($hookmanager->resArray['picto'])) { // Add entries for tabs
234 $picto = $hookmanager->resArray['picto'];
235 }
236 if (!empty($hookmanager->resArray['head'])) { // Add entries for tabs
237 $head = array_merge($head, $hookmanager->resArray['head']);
238 }
239 if (!empty($hookmanager->resArray['arrayoftype'])) { // Add entries from hook
240 foreach ($hookmanager->resArray['arrayoftype'] as $key => $val) {
241 $arrayoftype[$key] = $val;
242 }
243 }
244}
245
246// Load the main $object for statistics
247if ($objecttype) {
248 try {
249 if (!empty($arrayoftype[$objecttype]['ClassPath'])) {
250 $fileforclass = $arrayoftype[$objecttype]['ClassPath'];
251 } else {
252 $fileforclass = "/".$objecttype."/class/".$objecttype.".class.php";
253 }
254 $ObjectClassName = null;
255
256 if ($fileforclass !== null) {
257 dol_include_once($fileforclass);
258
259 $ObjectClassName = $arrayoftype[$objecttype]['ObjectClassName'];
260 }
261 if (!empty($ObjectClassName)) {
262 if (class_exists($ObjectClassName)) {
263 $object = new $ObjectClassName($db);
264 } else {
265 print 'Failed to load class for type '.$objecttype.'. Class file found but Class object named '.$ObjectClassName.' not found.';
266 }
267 } else {
268 print 'Failed to load class for type '.$objecttype.'. Class file name is unknown.';
269 }
270 } catch (Exception $e) {
271 print 'Failed to load class for type '.$objecttype.'. Class path not found.';
272 }
273}
274
275'@phan-var-force CommonObject $object';
276
277// Security check
278//$socid = 0;
279if ($user->socid > 0) { // Protection if external user
280 //$socid = $user->socid;
281 accessforbidden('Access forbidden to external users');
282}
283
284// Fetch optionals attributes and labels
285$extrafields->fetch_name_optionals_label('all'); // We load all extrafields definitions for all objects
286//$extrafields->fetch_name_optionals_label($object->table_element_line);
287
288if (!empty($object->table_element)) {
289 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
290} else {
291 $search_array_options = array();
292}
293
294$search_component_params = array('');
295$search_component_params_hidden = trim(GETPOST('search_component_params_hidden', 'alphanohtml'));
296$search_component_params_input = trim(GETPOST('search_component_params_input', 'alphanohtml'));
297//var_dump($search_component_params_hidden);
298//var_dump($search_component_params_input);
299
300// If string is not an universal filter string, we try to convert it into universal filter syntax string
301$errorstr = '';
302forgeSQLFromUniversalSearchCriteria($search_component_params_input, $errorstr); // Try conversion UFS->SQL
303//var_dump($errorstr);
304if ($errorstr) {
305 $value = $search_component_params_input;
306
307 $value = preg_replace('/([a-z\.]+)\s*([!<>=]+|in|notin|like|notlike)\s*/', '\1:\2:', $value); // Clean string 'x < 10' into 'x:<:10' so we can then explode on space to get all AND tests to do
308 $value = preg_replace('/\s*\|\s*/', '|', $value);
309 //var_dump($value);
310
311 $crits = explode(' ', trim($value)); // the string after the name of the field. Explode on each AND
312 $res = '';
313
314 $i1 = 0; // count the nb of and criteria added (all fields / criteria)
315 foreach ($crits as $crit) { // Loop on each AND criteria
316 $crit = trim($crit);
317
318 $i2 = 0; // count the nb of valid criteria added for this first criteria
319 $newres = '';
320 $tmpcrits = explode('|', $crit);
321 $i3 = 0; // count the nb of valid criteria added for this current field
322 foreach ($tmpcrits as $tmpcrit) {
323 if ($tmpcrit !== '0' && empty($tmpcrit)) {
324 continue;
325 }
326 $tmpcrit = trim($tmpcrit);
327 //var_dump($tmpcrit);
328
329 $errorstr = '';
330 $parenthesislevel = 0;
331 $rescheckfilter = dolCheckFilters($tmpcrit, $errorstr, $parenthesislevel);
332 if ($rescheckfilter) {
333 while ($parenthesislevel > 0) {
334 $tmpcrit = preg_replace('/^\‍(/', '', preg_replace('/\‍)$/', '', $tmpcrit));
335 $parenthesislevel--;
336 }
337 }
338
339 $field = preg_replace('/(:[!<>=\s]+:|:in:|:notin:|:like:|:notlike:).*$/', '', $tmpcrit); // the name of the field
340 $tmpcrit = preg_replace('/^.*(:[!<>=\s]+:|:in:|:notin:|:like:|:notlike:)/', '\1', $tmpcrit); // the condition after the name of the field
341 //var_dump($field); var_dump($tmpcrit); var_dump($i3);
342
343 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
344
345 $operator = '=';
346 $newcrit = preg_replace('/(:[!<>=\s]+:|:in:|:notin:|:like:|:notlike:)/', '', $tmpcrit);
347 //var_dump($newcrit);
348
349 $reg = array();
350 preg_match('/:([!<>=\s]+|in|notin|like|notlike):/', $tmpcrit, $reg);
351 if (!empty($reg[1])) {
352 $operator = $reg[1];
353 }
354 if ($newcrit != '') {
355 if (!preg_match('/^\'[^\']*\'$/', $newcrit)) {
356 $numnewcrit = price2num($newcrit);
357 $newres .= '('.$field.':'.$operator.':'.((float) $numnewcrit).')';
358 } else {
359 $newres .= '('.$field.':'.$operator.":".((string) $newcrit).')';
360 }
361 $i3++; // a criteria was added to string
362 }
363 }
364 $i2++; // a criteria for 1 more field was added to string
365
366 if ($newres) {
367 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
368 }
369 $i1++;
370 }
371 $res = "(".$res.")";
372
373 //var_dump($res);exit;
374 $search_component_params_input = $res;
375}
376
377$arrayofandtagshidden = dolForgeExplodeAnd($search_component_params_hidden);
378$arrayofandtagsinput = dolForgeExplodeAnd($search_component_params_input);
379
380$search_component_params_hidden = implode(' AND ', array_merge($arrayofandtagshidden, $arrayofandtagsinput));
381//var_dump($search_component_params_hidden);
382
383$MAXUNIQUEVALFORGROUP = 20;
384$MAXMEASURESINBARGRAPH = 20;
385$SHOWLEGEND = (isset($SHOWLEGEND) ? $SHOWLEGEND : 1);
386
387$YYYY = substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1).substr($langs->trans("Year"), 0, 1);
388$MM = substr($langs->trans("Month"), 0, 1).substr($langs->trans("Month"), 0, 1);
389$DD = substr($langs->trans("Day"), 0, 1).substr($langs->trans("Day"), 0, 1);
390$HH = substr($langs->trans("Hour"), 0, 1).substr($langs->trans("Hour"), 0, 1);
391$MI = substr($langs->trans("Minute"), 0, 1).substr($langs->trans("Minute"), 0, 1);
392$SS = substr($langs->trans("Second"), 0, 1).substr($langs->trans("Second"), 0, 1);
393
394$arrayoffilterfields = array();
395$arrayofmesures = array();
396$arrayofxaxis = array();
397$arrayofgroupby = array();
398$arrayofyaxis = array();
399$arrayofvaluesforgroupby = array();
400
401$features = '';
402if (!empty($object->element)) {
403 $features = $object->element;
404} else {
405 $features = '';
406}
407if (!empty($object->element_for_permission)) {
408 $features = $object->element_for_permission;
409} else {
410 $features .= (empty($object->module) ? '' : '@'.$object->module);
411}
412
413// $arrayoftype contains several features
414// Test on permission can be done on a given selected feature only
415
416// Security check (do not stop here, get only result to show message later)
417$resultcheck = restrictedArea($user, $features, 0, '', '', 'fk_soc', 'rowid', 0, 1);
418
419
420/*
421 * Actions
422 */
423
424// None
425
426
427
428/*
429 * View
430 */
431
432$form = new Form($db);
433$formother = new FormOther($db);
434
435if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
436 llxHeader('', $langs->transnoentitiesnoconv('CustomReports'), '');
437
438 if (empty($head)) {
439 print dol_get_fiche_head($head, 'customreports', $title, -2, $picto);
440 } else {
441 print dol_get_fiche_head($head, 'customreports', $title, -1, $picto);
442 }
443}
444
445// Define $newarrayoftype that is array of object available for report
446$newarrayoftype = array();
447foreach ($arrayoftype as $key => $val) {
448 if (dol_eval((string) $val['enabled'], 1, 1, '1')) {
449 $newarrayoftype[$key] = $arrayoftype[$key];
450 }
451 if (!empty($val['langs'])) {
452 $langs->load($val['langs']);
453 }
454}
455
456$count = 0;
457$label = '';
458if (array_key_exists($objecttype, $newarrayoftype)) {
459 $label = $langs->trans($newarrayoftype[$objecttype]['label']);
460}
461$arrayoffilterfields = fillArrayOfFilterFields($object, 't', $label, $arrayoffilterfields, 0, $count);
462$arrayoffilterfields = dol_sort_array($arrayoffilterfields, 'position', 'asc', 0, 0, 1);
463
464$count = 0;
465$arrayofmesures = fillArrayOfMeasures($object, 't', $label, $arrayofmesures, 0, $count);
466$arrayofmesures = dol_sort_array($arrayofmesures, 'position', 'asc', 0, 0, 1);
467
468$count = 0;
469$arrayofxaxis = fillArrayOfXAxis($object, 't', $label, $arrayofxaxis, 0, $count);
470$arrayofxaxis = dol_sort_array($arrayofxaxis, 'position', 'asc', 0, 0, 1);
471
472$count = 0;
473$arrayofgroupby = fillArrayOfGroupBy($object, 't', $label, $arrayofgroupby, 0, $count);
474$arrayofgroupby = dol_sort_array($arrayofgroupby, 'position', 'asc', 0, 0, 1);
475
476
477// Check parameters
478if ($action == 'viewgraph') {
479 if (!count($search_measures)) {
480 setEventMessages($langs->trans("AtLeastOneMeasureIsRequired"), null, 'warnings');
481 } elseif ($mode == 'graph' && is_array($search_xaxis) && count($search_xaxis) > 1) {
482 setEventMessages($langs->trans("OnlyOneFieldForXAxisIsPossible"), null, 'warnings');
483 $search_xaxis = array(0 => $search_xaxis[0]);
484 }
485 if (count($search_groupby) >= 2) {
486 setEventMessages($langs->trans("ErrorOnlyOneFieldForGroupByIsPossible"), null, 'warnings');
487 $search_groupby = array(0 => $search_groupby[0]);
488 }
489 if (!count($search_xaxis)) {
490 setEventMessages($langs->trans("AtLeastOneXAxisIsRequired"), null, 'warnings');
491 } elseif ($mode == 'graph' && $search_graph == 'bars' && count($search_measures) > $MAXMEASURESINBARGRAPH) {
492 $langs->load("errors");
493 setEventMessages($langs->trans("GraphInBarsAreLimitedToNMeasures", $MAXMEASURESINBARGRAPH), null, 'warnings');
494 $search_graph = 'lines';
495 }
496}
497
498// Get all possible values of fields when a 'group by' is set, and save this into $arrayofvaluesforgroupby
499// $arrayofvaluesforgroupby will be used to forge lael of each grouped series
500if (count($search_groupby)) {
501 $fieldtocount = '';
502 foreach ($search_groupby as $gkey => $gval) {
503 $gvalwithoutprefix = preg_replace('/^[a-z]+\./i', '', $gval);
504 $gvalsanitized = preg_replace('/[^a-z0-9\._\-]+/i', '', $gval);
505
506 if (preg_match('/\-year$/', $gvalsanitized)) {
507 $tmpval = preg_replace('/\-year$/', '', $gvalsanitized);
508 $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y')";
509 } elseif (preg_match('/\-month$/', $gvalsanitized)) {
510 $tmpval = preg_replace('/\-month$/', '', $gvalsanitized);
511 $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m')";
512 } elseif (preg_match('/\-day$/', $gvalsanitized)) {
513 $tmpval = preg_replace('/\-day$/', '', $gvalsanitized);
514 $fieldtocount .= 'DATE_FORMAT('.$tmpval.", '%Y-%m-%d')";
515 } else {
516 $fieldtocount = $gvalsanitized;
517 }
518
519 $sanitizedfieldtocount = $fieldtocount;
520 $sql = "SELECT DISTINCT ".$sanitizedfieldtocount." as val"; // $fieldtocount has been sanitized by previous lines as we can't use db->sanitie()
521
522 if (strpos($fieldtocount, 'te') === 0) {
523 $tabletouse = $object->table_element;
524 $tablealiastouse = 'te';
525 if (!empty($arrayofgroupby[$gval])) {
526 $tmpval = explode('.', $gval);
527 $tabletouse = $arrayofgroupby[$gval]['table'];
528 $tablealiastouse = $tmpval[0];
529 }
530 //var_dump($tablealiastouse);exit;
531
532 //$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element."_extrafields as te";
533 $sql .= " FROM ".MAIN_DB_PREFIX.$tabletouse."_extrafields as ".$tablealiastouse;
534 } else {
535 $tabletouse = $object->table_element;
536 $tablealiastouse = 't';
537 if (!empty($arrayofgroupby[$gval])) {
538 $tmpval = explode('.', $gval);
539 $tabletouse = $arrayofgroupby[$gval]['table'];
540 $tablealiastouse = $tmpval[0];
541 }
542 $sql .= " FROM ".MAIN_DB_PREFIX.$tabletouse." as ".$tablealiastouse;
543 }
544
545 // Add a where here keeping only the criteria on $tabletouse
546 /* TODO
547 if ($search_component_params_hidden) {
548 $errormessage = '';
549 $sql .= forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage);
550 }
551 */
552
553 $sql .= " LIMIT ".((int) ($MAXUNIQUEVALFORGROUP + 1));
554
555 //print $sql;
556 $resql = $db->query($sql);
557 if (!$resql) {
559 }
560
561 while ($obj = $db->fetch_object($resql)) {
562 if (is_null($obj->val)) {
563 $keytouse = '__NULL__';
564 $valuetranslated = $langs->transnoentitiesnoconv("NotDefined");
565 } elseif ($obj->val === '') {
566 $keytouse = '';
567 $valuetranslated = $langs->transnoentitiesnoconv("Empty");
568 } else {
569 $keytouse = (string) $obj->val;
570 $valuetranslated = $obj->val;
571 }
572
573 $regs = array();
574 if (isset($object->fields[$gvalwithoutprefix])) {
575 if (!empty($object->fields[$gvalwithoutprefix]['arrayofkeyval'])) {
576 $valuetranslated = $object->fields[$gvalwithoutprefix]['arrayofkeyval'][$obj->val];
577 if (is_null($valuetranslated)) {
578 $valuetranslated = $langs->transnoentitiesnoconv("UndefinedKey");
579 }
580 $valuetranslated = $langs->trans($valuetranslated);
581 } elseif (preg_match('/integer:([^:]+):([^:]+)$/', $object->fields[$gvalwithoutprefix]['type'], $regs)) {
582 $classname = $regs[1];
583 $classpath = $regs[2];
584 dol_include_once($classpath);
585 if (class_exists($classname)) {
586 $tmpobject = new $classname($db);
587 '@phan-var-force CommonObject $tmpobject';
588 $tmpobject->fetch($obj->val);
589 foreach ($tmpobject->fields as $fieldkey => $field) {
590 if ($field['showoncombobox']) {
591 $valuetranslated = $tmpobject->$fieldkey;
592 //if ($valuetranslated == '-') $valuetranslated = $langs->transnoentitiesnoconv("Unknown")
593 break;
594 }
595 }
596 //$valuetranslated = $tmpobject->ref.'eee';
597 }
598 }
599 }
600
601 $arrayofvaluesforgroupby['g_'.$gkey][$keytouse] = $valuetranslated;
602 }
603 // Add also the possible NULL value if field is a parent field that is not a strict join
604 $tmpfield = explode('.', $gval);
605 if ($tmpfield[0] != 't' || (isset($object->fields[$tmpfield[1]]) && is_array($object->fields[$tmpfield[1]]) && empty($object->fields[$tmpfield[1]]['notnull']))) {
606 dol_syslog("The group by field ".$gval." may be null (because field is null or it is a left join), so we add __NULL__ entry in list of possible values");
607 //var_dump($gval); var_dump($object->fields);
608 $arrayofvaluesforgroupby['g_'.$gkey]['__NULL__'] = $langs->transnoentitiesnoconv("NotDefined");
609 }
610
611 if (is_array($arrayofvaluesforgroupby['g_'.$gkey])) {
612 asort($arrayofvaluesforgroupby['g_'.$gkey]);
613 }
614
615 // Add a protection/error to refuse the request if number of differentr values for the group by is higher than $MAXUNIQUEVALFORGROUP
616 if (is_array($arrayofvaluesforgroupby['g_'.$gkey]) && count($arrayofvaluesforgroupby['g_'.$gkey]) > $MAXUNIQUEVALFORGROUP) {
617 $langs->load("errors");
618
619 if (strpos($fieldtocount, 'te') === 0) { // This is a field of an extrafield
620 //if (!empty($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix])) {
621 // $langs->load($extrafields->attributes[$object->table_element]['langfile'][$gvalwithoutprefix]);
622 //}
623 $keyforlabeloffield = $extrafields->attributes[$object->table_element]['label'][$gvalwithoutprefix];
624 $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
625 } elseif (strpos($fieldtocount, 't__') === 0) { // This is a field of a foreign key
626 $reg = array();
627 if (preg_match('/^(.*)\.(.*)/', $gvalwithoutprefix, $reg)) {
628 /*
629 $gvalwithoutprefix = preg_replace('/\..*$/', '', $gvalwithoutprefix);
630 $gvalwithoutprefix = preg_replace('/^t__/', '', $gvalwithoutprefix);
631 $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
632 $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
633 */
634 $labeloffield = $arrayofgroupby[$fieldtocount]['labelnohtml'];
635 } else {
636 $labeloffield = 'FK_ISSUE'; // $langs->transnoentitiesnoconv($keyforlabeloffield);
637 }
638 } else { // This is a common field
639 $reg = array();
640 if (preg_match('/^(.*)\-(year|month|day)/', $gvalwithoutprefix, $reg)) {
641 $gvalwithoutprefix = preg_replace('/\-(year|month|day)/', '', $gvalwithoutprefix);
642 $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
643 $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield).'-'.$reg[2];
644 } else {
645 $keyforlabeloffield = $object->fields[$gvalwithoutprefix]['label'];
646 $labeloffield = $langs->transnoentitiesnoconv($keyforlabeloffield);
647 }
648 }
649 //var_dump($labeloffield);
650 setEventMessages($langs->transnoentitiesnoconv("ErrorTooManyDifferentValueForSelectedGroupBy", (string) $MAXUNIQUEVALFORGROUP, (string) $labeloffield), null, 'warnings');
651 $search_groupby = array();
652 }
653
654 $db->free($resql);
655 }
656}
657//var_dump($arrayofvaluesforgroupby);exit;
658
659
660if (!$resultcheck) {
661 print '<div class="error">';
662 print $langs->trans("NotEnoughPermissions");
663 print '</div>';
664}
665
666
667
668//$tmparray = dol_getdate(dol_now());
669//$endyear = $tmparray['year'];
670//$endmonth = $tmparray['mon'];
671//$datelastday = dol_get_last_day($endyear, $endmonth, 1);
672//$startyear = $endyear - 2;
673
674$param = '';
675
676
677if (!defined('MAIN_CUSTOM_REPORT_KEEP_GRAPH_ONLY')) {
678 print '<form method="post" action="'.$_SERVER['PHP_SELF'].'" autocomplete="off">';
679 print '<input type="hidden" name="token" value="'.newToken().'">';
680 print '<input type="hidden" name="action" value="viewgraph">';
681 print '<input type="hidden" name="tabfamily" value="'.(string) $tabfamily.'">';
682
683 $viewmode = '';
684
685 $viewmode .= '<div class="divadvancedsearchfield">';
686 $arrayofgraphs = array('bars' => 'Bars', 'lines' => 'Lines'); // also 'pies'
687 $viewmode .= '<div class="inline-block opacitymedium"><span class="fas fa-chart-area paddingright" title="'.$langs->trans("Graph").'"></span>'.$langs->trans("Graph").'</div> ';
688 $viewmode .= $form->selectarray('search_graph', $arrayofgraphs, $search_graph, 0, 0, 0, '', 1, 0, 0, '', 'graphtype width100');
689 $viewmode .= '</div>';
690
691 $num = 0;
692 $massactionbutton = '';
693 $nav = '';
694 $newcardbutton = '';
695 $limit = 0;
696
697 print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, -1, 'object_action', 0, $nav.'<span class="marginleftonly"></span>'.$newcardbutton, '', $limit, 1, 0, 1, $viewmode);
698
699
700 foreach ($newarrayoftype as $tmpkey => $tmpval) {
701 $newarrayoftype[$tmpkey]['data-html'] = img_picto('', $tmpval['picto'], 'class="pictofixedwidth"').$langs->trans($tmpval['label']);
702 $newarrayoftype[$tmpkey]['label'] = $langs->trans($tmpval['label']);
703 }
704
705 print '<div class="liste_titre liste_titre_bydiv liste_titre_bydiv_inlineblock liste_titre_bydiv_nothingafter centpercent">';
706
707 // Select object
708 print '<div class="divadvancedsearchfield center floatnone">';
709 print '<div class="inline-block"><span class="opacitymedium">'.$langs->trans("StatisticsOn").'</span></div> ';
710
711 print $form->selectarray('objecttype', $newarrayoftype, $objecttype, 0, 0, 0, '', 1, 0, 0, '', 'minwidth250', 1, '', 0, 1);
712 if (empty($conf->use_javascript_ajax)) {
713 print '<input type="submit" class="button buttongen button-save nomargintop" name="changeobjecttype" value="'.$langs->trans("Refresh").'">';
714 } else {
715 print '<!-- js code to reload page with good object type -->
716 <script nonce="'.getNonce().'" type="text/javascript">
717 jQuery(document).ready(function() {
718 jQuery("#objecttype").change(function() {
719 console.log("Reload for "+jQuery("#objecttype").val());
720 location.href = "'.$_SERVER["PHP_SELF"].'?objecttype="+jQuery("#objecttype").val()+"'.($tabfamily ? '&tabfamily='.urlencode($tabfamily) : '').(GETPOSTINT('show_search_component_params_hidden') ? '&show_search_component_params_hidden='.((int) GETPOSTINT('show_search_component_params_hidden')) : '').'";
721 });
722 });
723 </script>';
724 }
725 print '</div><div class="clearboth"></div>';
726
727 if (!empty($newarrayoftype)) {
728 // Filter (you can use param &show_search_component_params_hidden=1 for debug)
729 if (!empty($object)) {
730 print '<div class="divadvancedsearchfield">';
731 print $form->searchComponent(array($object->element => $object->fields), $search_component_params, array(), $search_component_params_hidden, $arrayoffilterfields);
732 print '</div>';
733 }
734
735 // YAxis (add measures into array)
736 $count = 0;
737 //var_dump($arrayofmesures);
738 print '<div class="divadvancedsearchfield clearboth">';
739 print '<div class="inline-block"><span class="fas fa-ruler-combined paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Measures")).'"></span><span class="fas fa-caret-left caretleftaxis" title="'.dol_escape_htmltag($langs->trans("Measures")).'"></span></div>';
740 $simplearrayofmesures = array();
741 foreach ($arrayofmesures as $key => $val) {
742 $simplearrayofmesures[$key] = $arrayofmesures[$key]['label'];
743 }
744 print $form->multiselectarray('search_measures', $simplearrayofmesures, $search_measures, 0, 0, 'minwidth300 widthcentpercentminusx', 1, 0, '', '', $langs->transnoentitiesnoconv("Measures")); // Fill the array $arrayofmeasures with possible fields
745 print '</div>';
746
747 // XAxis
748 $count = 0;
749 print '<div class="divadvancedsearchfield">';
750 print '<div class="inline-block"><span class="fas fa-ruler-combined paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("XAxis")).'"></span><span class="fas fa-caret-down caretdownaxis" title="'.dol_escape_htmltag($langs->trans("XAxis")).'"></span></div>';
751 //var_dump($arrayofxaxis);
752 print $formother->selectXAxisField($object, $search_xaxis, $arrayofxaxis, $langs->trans("XAxis"), 'minwidth300 maxwidth400 widthcentpercentminusx'); // Fill the array $arrayofxaxis with possible fields
753 print '</div>';
754
755 // Group by
756 $count = 0;
757 print '<div class="divadvancedsearchfield">';
758 print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-horizontal paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("GroupBy")).'"></span></div>';
759 print $formother->selectGroupByField($object, $search_groupby, $arrayofgroupby, 'minwidth250 maxwidth300 widthcentpercentminusx', $langs->trans("GroupBy")); // Fill the array $arrayofgroupby with possible fields
760 print '</div>';
761 }
762
763 if ($mode == 'grid') {
764 // YAxis
765 print '<div class="divadvancedsearchfield">';
766 foreach ($object->fields as $key => $val) {
767 if (empty($val['measure']) && (!isset($val['enabled']) || dol_eval((string) $val['enabled'], 1, 1, '1'))) {
768 if (in_array($key, array('id', 'rowid', 'entity', 'last_main_doc', 'extraparams'))) {
769 continue;
770 }
771 if (preg_match('/^fk_/', $key)) {
772 continue;
773 }
774 if (in_array($val['type'], array('html', 'text'))) {
775 continue;
776 }
777 if (in_array($val['type'], array('timestamp', 'date', 'datetime'))) {
778 $arrayofyaxis['t.'.$key.'-year'] = array(
779 'label' => $langs->trans($val['label']).' ('.$YYYY.')',
780 'position' => $val['position'],
781 'table' => $object->table_element
782 );
783 $arrayofyaxis['t.'.$key.'-month'] = array(
784 'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.')',
785 'position' => $val['position'],
786 'table' => $object->table_element
787 );
788 $arrayofyaxis['t.'.$key.'-day'] = array(
789 'label' => $langs->trans($val['label']).' ('.$YYYY.'-'.$MM.'-'.$DD.')',
790 'position' => $val['position'],
791 'table' => $object->table_element
792 );
793 } else {
794 $arrayofyaxis['t.'.$key] = array(
795 'label' => $val['label'],
796 'position' => (int) $val['position'],
797 'table' => $object->table_element
798 );
799 }
800 }
801 }
802 // Add measure from extrafields
803 if ($object->isextrafieldmanaged) {
804 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
805 if (!empty($extrafields->attributes[$object->table_element]['totalizable'][$key]) && (!isset($extrafields->attributes[$object->table_element]['enabled'][$key]) || dol_eval((string) $extrafields->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'))) {
806 $arrayofyaxis['te.'.$key] = array(
807 'label' => $extrafields->attributes[$object->table_element]['label'][$key],
808 'position' => (int) $extrafields->attributes[$object->table_element]['pos'][$key],
809 'table' => $object->table_element
810 );
811 }
812 }
813 }
814 $arrayofyaxis = dol_sort_array($arrayofyaxis, 'position');
815 $arrayofyaxislabel = array();
816 foreach ($arrayofyaxis as $key => $val) {
817 $arrayofyaxislabel[$key] = $val['label'];
818 }
819 print '<div class="inline-block opacitymedium"><span class="fas fa-ruler-vertical paddingright" title="'.$langs->trans("YAxis").'"></span>'.$langs->trans("YAxis").'</div> ';
820 print $form->multiselectarray('search_yaxis', $arrayofyaxislabel, $search_yaxis != null ? $search_yaxis : array(), 0, 0, 'minwidth100', 1);
821 print '</div>';
822 }
823
824 if (!empty($newarrayoftype)) {
825 print '<div class="divadvancedsearchfield">';
826 print '<input type="submit" class="button buttongen button-save nomargintop" value="'.$langs->trans("Refresh").'">';
827 print '</div>';
828 }
829
830 print '</div>';
831 print '</form>';
832}
833
834// Generate the SQL request
835$sql = '';
836if (!empty($search_measures) && !empty($search_xaxis)) {
837 $errormessage = '';
838
839 $fieldid = 'rowid';
840
841 $sql = "SELECT ";
842 foreach ($search_xaxis as $key => $val) {
843 if (preg_match('/\-year$/', $val)) {
844 $tmpval = preg_replace('/\-year$/', '', $val);
845 $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as x_".$key.', ';
846 } elseif (preg_match('/\-month$/', $val)) {
847 $tmpval = preg_replace('/\-month$/', '', $val);
848 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as x_".$key.', ';
849 } elseif (preg_match('/\-day$/', $val)) {
850 $tmpval = preg_replace('/\-day$/', '', $val);
851 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as x_".$key.', ';
852 } else {
853 $sql .= $val." as x_".$key.", ";
854 }
855 }
856 if (!empty($search_groupby)) {
857 foreach ($search_groupby as $key => $val) {
858 if (preg_match('/\-year$/', $val)) {
859 $tmpval = preg_replace('/\-year$/', '', $val);
860 $sql .= "DATE_FORMAT(".$tmpval.", '%Y') as g_".$key.', ';
861 } elseif (preg_match('/\-month$/', $val)) {
862 $tmpval = preg_replace('/\-month$/', '', $val);
863 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m') as g_".$key.', ';
864 } elseif (preg_match('/\-day$/', $val)) {
865 $tmpval = preg_replace('/\-day$/', '', $val);
866 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d') as g_".$key.', ';
867 } else {
868 $sql .= $val." as g_".$key.", ";
869 }
870 }
871 }
872 foreach ($search_measures as $key => $val) {
873 if ($val == 't.count') {
874 $sql .= "COUNT(t.".$fieldid.") as y_".$key.', ';
875 } elseif (preg_match('/\-sum$/', $val)) {
876 $tmpval = preg_replace('/\-sum$/', '', $val);
877 $sql .= "SUM(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
878 } elseif (preg_match('/\-average$/', $val)) {
879 $tmpval = preg_replace('/\-average$/', '', $val);
880 $sql .= "AVG(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
881 } elseif (preg_match('/\-min$/', $val)) {
882 $tmpval = preg_replace('/\-min$/', '', $val);
883 $sql .= "MIN(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
884 } elseif (preg_match('/\-max$/', $val)) {
885 $tmpval = preg_replace('/\-max$/', '', $val);
886 $sql .= "MAX(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
887 } elseif (preg_match('/\-stddevpop$/', $val)) {
888 $tmpval = preg_replace('/\-stddevpop$/', '', $val);
889 $sql .= "STDDEV_POP(".$db->ifsql($tmpval.' IS NULL', '0', $tmpval).") as y_".$key.", ";
890 }
891 }
892 $sql = preg_replace('/,\s*$/', '', $sql);
893 $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t";
894 // Add measure from extrafields
895 if ($object->isextrafieldmanaged) {
896 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as te ON te.fk_object = t.".$fieldid;
897 }
898 // Add table for link on multientity
899 if ($object->ismultientitymanaged) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
900 if ($object->ismultientitymanaged == 1) {
901 // No table to add here
902 } else {
903 $tmparray = explode('@', $object->ismultientitymanaged);
904 $sql .= " INNER JOIN ".MAIN_DB_PREFIX.$tmparray[1]." as parenttableforentity ON t.".$tmparray[0]." = parenttableforentity.rowid";
905 $sql .= " AND parenttableforentity.entity IN (".getEntity($tmparray[1]).")";
906 }
907 }
908
909 // Init the list of tables added. We include by default always the main table.
910 $listoftablesalreadyadded = array($object->table_element => $object->table_element);
911
912 // Add LEFT JOIN for all parent tables mentioned into the Xaxis
913 //var_dump($arrayofxaxis); var_dump($search_xaxis);
914 foreach ($search_xaxis as $key => $val) {
915 if (!empty($arrayofxaxis[$val])) {
916 $tmpval = explode('.', $val);
917 //var_dump($arrayofgroupby);
918 $tmpforloop = dolExplodeIntoArray($arrayofxaxis[$val]['tablefromt'], ',');
919 foreach ($tmpforloop as $tmptable => $tmptablealias) {
920 if (! in_array($tmptable, $listoftablesalreadyadded)) { // We do not add join for main table and tables already added
921 $tmpforexplode = explode('__', $tmptablealias);
922 $endpart = end($tmpforexplode);
923 $parenttableandfield = preg_replace('/__'.$endpart.'$/', '', $tmptablealias).'.'.$endpart;
924
925 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable." as ".$db->sanitize($tmptablealias)." ON ".$db->sanitize($parenttableandfield)." = ".$db->sanitize($tmptablealias).".rowid";
926 $listoftablesalreadyadded[$tmptable] = $tmptable;
927
928 if (preg_match('/^te/', $tmpval[0]) && preg_replace('/^t_/', 'te_', $tmptablealias) == $tmpval[0]) {
929 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable."_extrafields as ".$db->sanitize($tmpval[0])." ON ".$db->sanitize($tmpval[0]).".fk_object = ".$db->sanitize($tmptablealias).".rowid";
930 $listoftablesalreadyadded[$tmptable] = $tmptable;
931 }
932 }
933 }
934 } else {
935 $errormessage = 'Found a key into search_xaxis not found into arrayofxaxis';
936 }
937 }
938
939 // Add LEFT JOIN for all parent tables mentioned into the Group by
940 //var_dump($arrayofgroupby); var_dump($search_groupby);
941 foreach ($search_groupby as $key => $val) {
942 if (!empty($arrayofgroupby[$val])) {
943 $tmpval = explode('.', $val);
944 //var_dump($arrayofgroupby[$val]); var_dump($tmpval);
945 $tmpforloop = dolExplodeIntoArray($arrayofgroupby[$val]['tablefromt'], ',');
946 foreach ($tmpforloop as $tmptable => $tmptablealias) {
947 if (! in_array($tmptable, $listoftablesalreadyadded)) { // We do not add join for main table and tables already added
948 $tmpforexplode = explode('__', $tmptablealias);
949 $endpart = end($tmpforexplode);
950 $parenttableandfield = preg_replace('/__'.$endpart.'$/', '', $tmptablealias).'.'.$endpart;
951
952 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable." as ".$db->sanitize($tmptablealias)." ON ".$db->sanitize($parenttableandfield)." = ".$db->sanitize($tmptablealias).".rowid";
953 $listoftablesalreadyadded[$tmptable] = $tmptable;
954
955 if (preg_match('/^te/', $tmpval[0]) && preg_replace('/^t_/', 'te_', $tmptablealias) == $tmpval[0]) {
956 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable."_extrafields as ".$db->sanitize($tmpval[0])." ON ".$db->sanitize($tmpval[0]).".fk_object = ".$db->sanitize($tmptablealias).".rowid";
957 $listoftablesalreadyadded[$tmptable] = $tmptable;
958 }
959 }
960 }
961 } else {
962 $errormessage = 'Found a key into search_groupby not found into arrayofgroupby';
963 }
964 }
965
966 // Add LEFT JOIN for all parent tables mentioned into the Yaxis
967 //var_dump($arrayofgroupby); var_dump($search_groupby);
968 foreach ($search_measures as $key => $val) {
969 if (!empty($arrayofmesures[$val])) {
970 $tmpval = explode('.', $val);
971 //var_dump($arrayofgroupby);
972 $tmpforloop = dolExplodeIntoArray($arrayofmesures[$val]['tablefromt'], ',');
973 foreach ($tmpforloop as $tmptable => $tmptablealias) {
974 if (! in_array($tmptable, $listoftablesalreadyadded)) { // We do not add join for main table and tables already added
975 $tmpforexplode = explode('__', $tmptablealias);
976 $endpart = end($tmpforexplode);
977 $parenttableandfield = preg_replace('/__'.$endpart.'$/', '', $tmptablealias).'.'.$endpart;
978
979 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable." as ".$db->sanitize($tmptablealias)." ON ".$db->sanitize($parenttableandfield)." = ".$db->sanitize($tmptablealias).".rowid";
980 $listoftablesalreadyadded[$tmptable] = $tmptable;
981
982 if (preg_match('/^te/', $tmpval[0]) && preg_replace('/^t_/', 'te_', $tmptablealias) == $tmpval[0]) {
983 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable."_extrafields as ".$db->sanitize($tmpval[0])." ON ".$db->sanitize($tmpval[0]).".fk_object = ".$db->sanitize($tmptablealias).".rowid";
984 $listoftablesalreadyadded[$tmptable] = $tmptable;
985 }
986 }
987 }
988 } else {
989 $errormessage = 'Found a key into search_measures not found into arrayofmesures';
990 }
991 }
992
993 // Add LEFT JOIN for all tables mentioned into filter
994 if (!empty($search_component_params_hidden)) {
995 // Get all fields used into the filter
996 $matches = array();
997 preg_match_all('/\b(t[\w]*_[\w]*)\.(\w+(-\w+)?)/', $search_component_params_hidden, $matches);
998 $fieldsUsedInFilter = array_unique($matches[0]);
999
1000 // Remove fields used before to avoid double join
1001 $fieldsToRemove = array_merge($search_measures, $search_groupby, $search_xaxis);
1002 $fieldsUsedInFilter = array_diff($fieldsUsedInFilter, $fieldsToRemove);
1003
1004 foreach ($fieldsUsedInFilter as $key => $val) {
1005 if (!empty($arrayoffilterfields[$val])) {
1006 $tmpval = explode('.', $val);
1007 $tmpforloop = dolExplodeIntoArray($arrayoffilterfields[$val]['tablefromt'], ',');
1008 foreach ($tmpforloop as $tmptable => $tmptablealias) {
1009 if (! in_array($tmptable, $listoftablesalreadyadded)) { // We do not add join for main table and tables already added
1010 $tmpforexplode = explode('__', $tmptablealias);
1011 $endpart = end($tmpforexplode);
1012 $parenttableandfield = preg_replace('/__'.$endpart.'$/', '', $tmptablealias).'.'.$endpart;
1013
1014 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable." as ".$db->sanitize($tmptablealias)." ON ".$db->sanitize($parenttableandfield)." = ".$db->sanitize($tmptablealias).".rowid";
1015 $listoftablesalreadyadded[$tmptable] = $tmptable;
1016
1017 if (preg_match('/^te/', $tmpval[0]) && preg_replace('/^t_/', 'te_', $tmptablealias) == $tmpval[0]) {
1018 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$tmptable."_extrafields as ".$db->sanitize($tmpval[0])." ON ".$db->sanitize($tmpval[0]).".fk_object = ".$db->sanitize($tmptablealias).".rowid";
1019 $listoftablesalreadyadded[$tmptable] = $tmptable;
1020 }
1021 }
1022 }
1023 } else {
1024 $errormessage = 'Found a key into search_filterfields not found into arrayoffilterfields';
1025 }
1026 }
1027 }
1028
1029 $sql .= " WHERE 1 = 1";
1030 if ($object->ismultientitymanaged == 1) { // 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
1031 $sql .= " AND t.entity IN (".getEntity($object->element).")";
1032 }
1033 // Add the where here
1034 $sqlfilters = $search_component_params_hidden;
1035 if ($sqlfilters) {
1036 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage, 0, 0, 1);
1037
1038 // Replace date values by $db->idate(dol_mktime(...))
1039 $sql = preg_replace_callback(
1040 "/(\w+)\.(\w+)\s*(=|!=|<>|<|>|<=|>=)\s*'(\d{4})-(\d{2})-(\d{2})'/",
1045 function (array $matches): string {
1046 global $db;
1047 $column = $matches[1] . '.' . $matches[2];
1048 $operator = $matches[3];
1049 $year = (int) $matches[4];
1050 $month = (int) $matches[5];
1051 $day = (int) $matches[6];
1052
1053 $startOfDay = $db->idate(dol_mktime(0, 0, 0, $month, $day, $year));
1054 $endOfDay = $db->idate(dol_mktime(23, 59, 59, $month, $day, $year));
1055
1056 switch ($operator) {
1057 case "=":
1058 return "($column >= '$startOfDay' AND $column <= '$endOfDay')";
1059 case "!=":
1060 case "<>":
1061 return "NOT ($column >= '$startOfDay' AND $column <= '$endOfDay')";
1062 case "<":
1063 return "$column < '$startOfDay'";
1064 case ">":
1065 return "$column > '$endOfDay'";
1066 case "<=":
1067 return "$column <= '$endOfDay'";
1068 case ">=":
1069 return "$column >= '$startOfDay'";
1070 default:
1071 return "";
1072 }
1073 },
1074 $sql
1075 );
1076 }
1077 $sql .= " GROUP BY ";
1078 foreach ($search_xaxis as $key => $val) {
1079 if (preg_match('/\-year$/', $val)) {
1080 $tmpval = preg_replace('/\-year$/', '', $val);
1081 $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
1082 } elseif (preg_match('/\-month$/', $val)) {
1083 $tmpval = preg_replace('/\-month$/', '', $val);
1084 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
1085 } elseif (preg_match('/\-day$/', $val)) {
1086 $tmpval = preg_replace('/\-day$/', '', $val);
1087 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
1088 } else {
1089 $sql .= $val.", ";
1090 }
1091 }
1092 if (!empty($search_groupby)) {
1093 foreach ($search_groupby as $key => $val) {
1094 if (preg_match('/\-year$/', $val)) {
1095 $tmpval = preg_replace('/\-year$/', '', $val);
1096 $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
1097 } elseif (preg_match('/\-month$/', $val)) {
1098 $tmpval = preg_replace('/\-month$/', '', $val);
1099 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
1100 } elseif (preg_match('/\-day$/', $val)) {
1101 $tmpval = preg_replace('/\-day$/', '', $val);
1102 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
1103 } else {
1104 $sql .= $val.', ';
1105 }
1106 }
1107 }
1108 $sql = preg_replace('/,\s*$/', '', $sql);
1109 $sql .= ' ORDER BY ';
1110 foreach ($search_xaxis as $key => $val) {
1111 if (preg_match('/\-year$/', $val)) {
1112 $tmpval = preg_replace('/\-year$/', '', $val);
1113 $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
1114 } elseif (preg_match('/\-month$/', $val)) {
1115 $tmpval = preg_replace('/\-month$/', '', $val);
1116 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
1117 } elseif (preg_match('/\-day$/', $val)) {
1118 $tmpval = preg_replace('/\-day$/', '', $val);
1119 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
1120 } else {
1121 $sql .= $val.', ';
1122 }
1123 }
1124 if (!empty($search_groupby)) {
1125 foreach ($search_groupby as $key => $val) {
1126 if (preg_match('/\-year$/', $val)) {
1127 $tmpval = preg_replace('/\-year$/', '', $val);
1128 $sql .= "DATE_FORMAT(".$tmpval.", '%Y'), ";
1129 } elseif (preg_match('/\-month$/', $val)) {
1130 $tmpval = preg_replace('/\-month$/', '', $val);
1131 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m'), ";
1132 } elseif (preg_match('/\-day$/', $val)) {
1133 $tmpval = preg_replace('/\-day$/', '', $val);
1134 $sql .= "DATE_FORMAT(".$tmpval.", '%Y-%m-%d'), ";
1135 } else {
1136 $sql .= $val.', ';
1137 }
1138 }
1139 }
1140 $sql = preg_replace('/,\s*$/', '', $sql);
1141
1142 // Can overwrite the SQL with a custom SQL string (when used as an include)
1143 if (!empty($customsql)) {
1144 $sql = $customsql;
1145 }
1146}
1147//print $sql;
1148
1149if ($errormessage) {
1150 print '<div class="warning">';
1151 print dol_escape_htmltag($errormessage);
1152 //print '<br>'.dol_escape_htmltag('SQL is '.$sql);
1153 print '</div>';
1154 $sql = '';
1155}
1156
1157$legend = array();
1158foreach ($search_measures as $key => $val) {
1159 $legend[] = $langs->trans($arrayofmesures[$val]['label']);
1160}
1161
1162$useagroupby = count($search_groupby);
1163//var_dump($useagroupby);
1164//var_dump($arrayofvaluesforgroupby);
1165
1166// Execute the SQL request
1167$totalnbofrecord = 0;
1168$data = array();
1169if ($sql) {
1170 $resql = $db->query($sql);
1171 if (!$resql) {
1172 print '<div class="warning">';
1173 print dol_escape_htmltag($db->lasterror());
1174 //print '<br>'.dol_escape_htmltag('SQL is '.$sql);
1175 print '</div>';
1176 } else {
1177 $ifetch = 0;
1178 $xi = 0;
1179 $oldlabeltouse = '';
1180 while ($obj = $db->fetch_object($resql)) {
1181 $ifetch++;
1182 if ($useagroupby) {
1183 $xval = $search_xaxis[0];
1184 $fieldforxkey = 'x_0';
1185 $xlabel = $obj->$fieldforxkey;
1186 $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
1187
1188 // Define $xlabel
1189 if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
1190 $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
1191 }
1192 $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->transnoentitiesnoconv("Empty") : $langs->transnoentitiesnoconv("NotDefined")));
1193
1194 if ($oldlabeltouse !== '' && ($labeltouse != $oldlabeltouse)) {
1195 $xi++; // Increase $xi
1196 }
1197 //var_dump($labeltouse.' '.$oldlabeltouse.' '.$xi);
1198 $oldlabeltouse = $labeltouse;
1199
1200 /* Example of value for $arrayofvaluesforgroupby
1201 * array (size=1)
1202 * 'g_0' =>
1203 * array (size=6)
1204 * 0 => string '0' (length=1)
1205 * '' => string 'Empty' (length=5)
1206 * '__NULL__' => string 'Not defined' (length=11)
1207 * 'done' => string 'done' (length=4)
1208 * 'processing' => string 'processing' (length=10)
1209 * 'undeployed' => string 'undeployed' (length=10)
1210 */
1211 foreach ($search_measures as $key => $val) {
1212 $gi = 0;
1213 foreach ($search_groupby as $gkey => $gval) {
1214 //var_dump('*** Fetch #'.$ifetch.' for labeltouse='.$labeltouse.' measure number '.$key.' and group g_'.$gi);
1215 //var_dump($arrayofvaluesforgroupby);
1216 foreach ($arrayofvaluesforgroupby['g_'.$gi] as $gvaluepossiblekey => $gvaluepossiblelabel) {
1217 $ykeysuffix = $gvaluepossiblelabel;
1218 $gvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $gval);
1219
1220 $fieldfory = 'y_'.$key;
1221 $fieldforg = 'g_'.$gi;
1222 $fieldforybis = 'y_'.$key.'_'.$ykeysuffix;
1223 //var_dump('gvaluepossiblekey='.$gvaluepossiblekey.' gvaluepossiblelabel='.$gvaluepossiblelabel.' ykeysuffix='.$ykeysuffix.' gval='.$gval.' gvalwithoutsuffix='.$gvalwithoutprefix);
1224 //var_dump('fieldforg='.$fieldforg.' obj->$fieldforg='.$obj->$fieldforg.' fieldfory='.$fieldfory.' obj->$fieldfory='.$obj->$fieldfory.' fieldforybis='.$fieldforybis);
1225
1226 if (!array_key_exists($xi, $data)) {
1227 $data[$xi] = array();
1228 }
1229
1230 if (!array_key_exists('label', $data[$xi])) {
1231 $data[$xi] = array();
1232 $data[$xi]['label'] = $labeltouse;
1233 }
1234
1235 $objfieldforg = $obj->$fieldforg;
1236 if (is_null($objfieldforg)) {
1237 $objfieldforg = '__NULL__';
1238 }
1239
1240 if ($gvaluepossiblekey == '0') { // $gvaluepossiblekey can have type int or string. So we create a special if, used when value is '0'
1241 //var_dump($objfieldforg.' == \'0\' -> '.($objfieldforg == '0'));
1242 if ($objfieldforg == '0') {
1243 // The record we fetch is for this group
1244 $data[$xi][$fieldforybis] = $obj->$fieldfory;
1245 } elseif (!isset($data[$xi][$fieldforybis])) {
1246 // The record we fetch is not for this group
1247 $data[$xi][$fieldforybis] = '0';
1248 }
1249 } else {
1250 //var_dump((string) $objfieldforg.' === '.(string) $gvaluepossiblekey.' -> '.((string) $objfieldforg === (string) $gvaluepossiblekey));
1251 if ((string) $objfieldforg === (string) $gvaluepossiblekey) {
1252 // The record we fetch is for this group
1253 $data[$xi][$fieldforybis] = $obj->$fieldfory;
1254 } elseif (!isset($data[$xi][$fieldforybis])) {
1255 // The record we fetch is not for this group
1256 $data[$xi][$fieldforybis] = '0';
1257 }
1258 }
1259 }
1260 //var_dump($data[$xi]);
1261 $gi++;
1262 }
1263 }
1264 } else { // No group by
1265 $xval = $search_xaxis[0];
1266 $fieldforxkey = 'x_0';
1267 $xlabel = $obj->$fieldforxkey;
1268 $xvalwithoutprefix = preg_replace('/^[a-z]+\./', '', $xval);
1269
1270 // Define $xlabel
1271 if (!empty($object->fields[$xvalwithoutprefix]['arrayofkeyval'])) {
1272 $xlabel = $object->fields[$xvalwithoutprefix]['arrayofkeyval'][$obj->$fieldforxkey];
1273 }
1274
1275 $labeltouse = (($xlabel || $xlabel == '0') ? dol_trunc($xlabel, 20, 'middle') : ($xlabel === '' ? $langs->transnoentitiesnoconv("Empty") : $langs->transnoentitiesnoconv("NotDefined")));
1276 $xarrayforallseries = array('label' => $labeltouse);
1277 foreach ($search_measures as $key => $val) {
1278 $fieldfory = 'y_'.$key;
1279 $xarrayforallseries[$fieldfory] = $obj->$fieldfory;
1280 }
1281 $data[$xi] = $xarrayforallseries;
1282 $xi++;
1283 }
1284 }
1285
1286 $totalnbofrecord = count($data);
1287 }
1288}
1289//var_dump($data);
1290
1291print '<!-- Section to show the result -->'."\n";
1292print '<div class="customreportsoutput'.($totalnbofrecord ? '' : ' customreportsoutputnotdata').'">';
1293
1294if (empty($newarrayoftype)) {
1295 $langs->load("admin");
1296 print info_admin($langs->trans("NoSupportedModulesHaveBeenActivated").' '.$langs->trans("YouCanEnableModulesFrom"), 0, 0, 'info');
1297}
1298
1299if ($mode == 'grid') {
1300 // TODO
1301}
1302
1303if ($mode == 'graph') {
1304 $WIDTH = '80%';
1305 $HEIGHT = (empty($_SESSION['dol_screenheight']) ? 400 : $_SESSION['dol_screenheight'] - 500);
1306
1307 // Show graph
1308 $px1 = new DolGraph();
1309 $mesg = $px1->isGraphKo();
1310 if (!$mesg) {
1311 //var_dump($legend);
1312 //var_dump($data);
1313 $px1->SetData($data);
1314 unset($data);
1315
1316 $arrayoftypes = array();
1317 foreach ($search_measures as $key => $val) {
1318 $arrayoftypes[] = $search_graph;
1319 }
1320
1321 $px1->SetLegend($legend);
1322 $px1->setShowLegend($SHOWLEGEND);
1323 $px1->SetMinValue((int) $px1->GetFloorMinValue());
1324 $px1->SetMaxValue($px1->GetCeilMaxValue());
1325 $px1->SetWidth($WIDTH);
1326 $px1->SetHeight($HEIGHT);
1327 $px1->SetYLabel($langs->trans("Y"));
1328 $px1->SetShading(3);
1329 $px1->SetHorizTickIncrement(1);
1330 $px1->SetCssPrefix("cssboxes");
1331 $px1->SetType($arrayoftypes);
1332 $px1->mode = 'depth';
1333 $px1->SetTitle('');
1334
1335 $dir = $conf->user->dir_temp;
1336 dol_mkdir($dir);
1337 // $customreportkey may be defined when using customreports.php as an include
1338 if (!empty($object->element)) {
1339 $filenamekey = $dir.'/customreport_'.$object->element.(empty($customreportkey) ? '' : $customreportkey).'.png';
1340 $fileurlkey = DOL_URL_ROOT.'/viewimage.php?modulepart=user&file=customreport_'.$object->element.(empty($customreportkey) ? '' : $customreportkey).'.png';
1341 }
1342
1343 if (isset($filenamekey) && isset($fileurlkey)) {
1344 $px1->draw($filenamekey, $fileurlkey);
1345 }
1346
1347 $texttoshow = $langs->trans("NoRecordFound");
1348 if (!GETPOSTISSET('search_measures') || !GETPOSTISSET('search_xaxis')) {
1349 $texttoshow = $langs->trans("SelectYourGraphOptionsFirst");
1350 }
1351
1352 print $px1->show($totalnbofrecord ? 0 : $texttoshow);
1353 }
1354}
1355
1356print '</div>';
1357
1358if ($sql && !defined('MAIN_CUSTOM_REPORT_KEEP_GRAPH_ONLY')) {
1359 // Show admin info
1360 print '<br>'.info_admin($langs->trans("SQLUsedForExport").':<br> '.$sql, 0, 0, '1', '', 'TechnicalInformation');
1361}
1362
1363
1364if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) {
1365 print dol_get_fiche_end();
1366
1367 llxFooter();
1368 // End of page
1369
1370 $db->close();
1371}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to build graphs.
Class to manage standard extra fields.
Class to manage generation of HTML components Only common components must be here.
Class to help generate other html components Only common components are here.
fillArrayOfGroupBy($object, $tablealias, $labelofobject, &$arrayofgroupby, $level=0, &$count=0, &$tablepath='')
Fill arrayofgroupby for an object.
fillArrayOfFilterFields($object, $tablealias, $labelofobject, &$arrayoffields, $level=0, &$count=0, &$tablepath='')
Fill array of possible filter fields for an object.
fillArrayOfMeasures($object, $tablealias, $labelofobject, &$arrayofmesures, $level=0, &$count=0, &$tablepath='')
Fill arrayofmesures for an object.
fillArrayOfXAxis($object, $tablealias, $labelofobject, &$arrayofxaxis, $level=0, &$count=0, &$tablepath='')
Fill arrayofmesures for an object.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='')
Show information in HTML for admin users or standard users.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
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...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.