1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* Copyright (C) 2023-2024 Laurent Destailleur <[email protected]> |
4
|
|
|
* Copyright (C) 2023-2024 Lionel Vessiller <[email protected]> |
5
|
|
|
* Copyright (C) 2023-2024 Patrice Andreani <[email protected]> |
6
|
|
|
* Copyright (C) 2024 Frédéric France <[email protected]> |
7
|
|
|
* Copyright (C) 2024 MDW <[email protected]> |
8
|
|
|
* Copyright (C) 2024 Rafael San José <[email protected]> |
9
|
|
|
* |
10
|
|
|
* This program is free software; you can redistribute it and/or modify |
11
|
|
|
* it under the terms of the GNU General Public License as published by |
12
|
|
|
* the Free Software Foundation; either version 3 of the License, or |
13
|
|
|
* (at your option) any later version. |
14
|
|
|
* |
15
|
|
|
* This program is distributed in the hope that it will be useful, |
16
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18
|
|
|
* GNU General Public License for more details. |
19
|
|
|
* |
20
|
|
|
* You should have received a copy of the GNU General Public License |
21
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace Dolibarr\Code\WebPortal\Classes; |
25
|
|
|
|
26
|
|
|
use DoliDB; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* \file htdocs/webportal/class/html.formlistwebportal.class.php |
30
|
|
|
* \ingroup webportal |
31
|
|
|
* \brief File of class with all html predefined components for WebPortal |
32
|
|
|
*/ |
33
|
|
|
|
34
|
|
|
use Dolibarr\Code\Societe\Classes\Societe; |
35
|
|
|
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/discount.class.php'; |
36
|
|
|
require_once constant('DOL_DOCUMENT_ROOT') . '/webportal/class/html.formwebportal.class.php'; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Class to manage generation of HTML components |
40
|
|
|
* Only common components for WebPortal must be here. |
41
|
|
|
* |
42
|
|
|
*/ |
43
|
|
|
class FormListWebPortal |
44
|
|
|
{ |
45
|
|
|
/** |
46
|
|
|
* @var string Action |
47
|
|
|
*/ |
48
|
|
|
public $action = ''; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var DoliDB Database |
52
|
|
|
*/ |
53
|
|
|
public $db; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var Form Instance of the Form |
57
|
|
|
*/ |
58
|
|
|
public $form; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var CommonObject Object |
62
|
|
|
*/ |
63
|
|
|
public $object; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var int Limit (-1 to get limit from conf, 0 no limit, or Nb to show) |
67
|
|
|
*/ |
68
|
|
|
public $limit = -1; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var int Page (1 by default) |
72
|
|
|
*/ |
73
|
|
|
public $page = 1; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var string Sort field |
77
|
|
|
*/ |
78
|
|
|
public $sortfield = ''; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var string Sort order |
82
|
|
|
*/ |
83
|
|
|
public $sortorder = ''; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var string Title key to translate |
87
|
|
|
*/ |
88
|
|
|
public $titleKey = ''; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var string Title desc key to translate |
92
|
|
|
*/ |
93
|
|
|
public $titleDescKey = ''; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @var string Page context |
97
|
|
|
*/ |
98
|
|
|
public $contextpage = ''; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @var array Search filters |
102
|
|
|
*/ |
103
|
|
|
public $search = array(); |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @var array Array of fields |
107
|
|
|
*/ |
108
|
|
|
public $arrayfields = array(); |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @var array Company static list (cache) |
112
|
|
|
*/ |
113
|
|
|
public $companyStaticList = array(); |
114
|
|
|
|
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Constructor |
118
|
|
|
* |
119
|
|
|
* @param DoliDB $db Database handler |
120
|
|
|
*/ |
121
|
|
|
public function __construct($db) |
122
|
|
|
{ |
123
|
|
|
$this->db = $db; |
124
|
|
|
$this->form = new FormWebPortal($this->db); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Init |
129
|
|
|
* |
130
|
|
|
* @param string $elementEn Element (english) : "propal", "order", "invoice" |
131
|
|
|
* @return void |
132
|
|
|
*/ |
133
|
|
|
public function init($elementEn) |
134
|
|
|
{ |
135
|
|
|
// keep compatibility |
136
|
|
|
if ($elementEn == 'commande') { |
137
|
|
|
$elementEn = 'order'; |
138
|
|
|
} elseif ($elementEn == 'facture') { |
139
|
|
|
$elementEn = 'invoice'; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
// load module libraries |
143
|
|
|
dol_include_once('/webportal/class/webportal' . $elementEn . '.class.php'); |
144
|
|
|
|
145
|
|
|
// Initialize technical objects |
146
|
|
|
$objectclass = 'WebPortal' . ucfirst($elementEn); |
147
|
|
|
$object = new $objectclass($this->db); |
148
|
|
|
|
149
|
|
|
// set form list |
150
|
|
|
$this->action = GETPOST('action', 'aZ09'); |
|
|
|
|
151
|
|
|
$this->object = $object; |
152
|
|
|
$this->limit = GETPOSTISSET('limit') ? GETPOSTINT('limit') : -1; |
153
|
|
|
$this->sortfield = GETPOST('sortfield', 'aZ09comma'); |
|
|
|
|
154
|
|
|
$this->sortorder = GETPOST('sortorder', 'aZ09comma'); |
|
|
|
|
155
|
|
|
$this->page = GETPOSTISSET('page') ? GETPOSTINT('page') : 1; |
156
|
|
|
$this->titleKey = $objectclass . 'ListTitle'; |
157
|
|
|
|
158
|
|
|
// Initialize array of search criteria |
159
|
|
|
//$search_all = GETPOST('search_all', 'alphanohtml'); |
160
|
|
|
$search = array(); |
161
|
|
|
foreach ($object->fields as $key => $val) { |
162
|
|
|
if (GETPOST('search_' . $key, 'alpha') !== '') { |
163
|
|
|
$search[$key] = GETPOST('search_' . $key, 'alpha'); |
164
|
|
|
} |
165
|
|
|
if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { |
166
|
|
|
$postDateStart = GETPOST('search_' . $key . '_dtstart', 'alphanohtml'); |
167
|
|
|
$postDateEnd = GETPOST('search_' . $key . '_dtend', 'alphanohtml'); |
168
|
|
|
// extract date YYYY-MM-DD for year, month and day |
169
|
|
|
$dateStartArr = explode('-', $postDateStart); |
170
|
|
|
$dateEndArr = explode('-', $postDateEnd); |
171
|
|
|
if (count($dateStartArr) == 3) { |
172
|
|
|
$dateStartYear = (int) $dateStartArr[0]; |
173
|
|
|
$dateStartMonth = (int) $dateStartArr[1]; |
174
|
|
|
$dateStartDay = (int) $dateStartArr[2]; |
175
|
|
|
$search[$key . '_dtstart'] = dol_mktime(0, 0, 0, $dateStartMonth, $dateStartDay, $dateStartYear); |
176
|
|
|
} |
177
|
|
|
if (count($dateEndArr) == 3) { |
178
|
|
|
$dateEndYear = (int) $dateEndArr[0]; |
179
|
|
|
$dateEndMonth = (int) $dateEndArr[1]; |
180
|
|
|
$dateEndDay = (int) $dateEndArr[2]; |
181
|
|
|
$search[$key . '_dtend'] = dol_mktime(23, 59, 59, $dateEndMonth, $dateEndDay, $dateEndYear); |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
$this->search = $search; |
186
|
|
|
|
187
|
|
|
// List of fields to search into when doing a "search in all" |
188
|
|
|
//$fieldstosearchall = array(); |
189
|
|
|
|
190
|
|
|
// Definition of array of fields for columns |
191
|
|
|
$arrayfields = array(); |
192
|
|
|
foreach ($object->fields as $key => $val) { |
193
|
|
|
// If $val['visible']==0, then we never show the field |
194
|
|
|
if (!empty($val['visible'])) { |
195
|
|
|
$visible = (int) dol_eval($val['visible'], 1); |
196
|
|
|
$arrayfields['t.' . $key] = array( |
197
|
|
|
'label' => $val['label'], |
198
|
|
|
'checked' => (($visible < 0) ? 0 : 1), |
199
|
|
|
'enabled' => (abs($visible) != 3 && (int) dol_eval($val['enabled'], 1)), |
200
|
|
|
'position' => $val['position'], |
201
|
|
|
'help' => isset($val['help']) ? $val['help'] : '' |
202
|
|
|
); |
203
|
|
|
} |
204
|
|
|
} |
205
|
|
|
if ($elementEn == 'invoice') { |
206
|
|
|
$arrayfields['remain_to_pay'] = array('type' => 'price', 'label' => 'RemainderToPay', 'checked' => 1, 'enabled' => 1, 'visible' => 1, 'position' => 10000, 'help' => '',); |
207
|
|
|
} |
208
|
|
|
$arrayfields['download_link'] = array('label' => 'File', 'checked' => 1, 'enabled' => 1, 'visible' => 1, 'position' => 10001, 'help' => '',); |
209
|
|
|
if ($elementEn == "propal" && getDolGlobalString("PROPOSAL_ALLOW_ONLINESIGN") != 0) { |
210
|
|
|
$arrayfields['signature_link'] = array('label' => 'Signature', 'checked' => 1, 'enabled' => 1, 'visible' => 1, 'position' => 10002, 'help' => '',); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
$object->fields = dol_sort_array($object->fields, 'position'); |
214
|
|
|
//$arrayfields['anotherfield'] = array('type'=>'integer', 'label'=>'AnotherField', 'checked'=>1, 'enabled'=>1, 'position'=>90, 'csslist'=>'right'); |
215
|
|
|
$arrayfields = dol_sort_array($arrayfields, 'position'); |
216
|
|
|
|
217
|
|
|
$this->arrayfields = $arrayfields; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* Do actions |
222
|
|
|
* |
223
|
|
|
* @return void |
224
|
|
|
*/ |
225
|
|
|
public function doActions() |
226
|
|
|
{ |
227
|
|
|
$object = $this->object; |
228
|
|
|
$search = $this->search; |
229
|
|
|
|
230
|
|
|
// Purge search criteria |
231
|
|
|
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers |
232
|
|
|
foreach ($object->fields as $key => $val) { |
233
|
|
|
$search[$key] = ''; |
234
|
|
|
if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { |
235
|
|
|
$search[$key . '_dtstart'] = ''; |
236
|
|
|
$search[$key . '_dtend'] = ''; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
$this->search = $search; |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* List for an element in the page context |
245
|
|
|
* |
246
|
|
|
* @param Context $context Context object |
247
|
|
|
* @return string Html output |
248
|
|
|
*/ |
249
|
|
|
public function elementList($context) |
250
|
|
|
{ |
251
|
|
|
global $conf, $hookmanager, $langs; |
252
|
|
|
|
253
|
|
|
$html = ''; |
254
|
|
|
|
255
|
|
|
// initialize |
256
|
|
|
$action = $this->action; |
257
|
|
|
$object = $this->object; |
258
|
|
|
$limit = $this->limit; |
259
|
|
|
$page = $this->page; |
260
|
|
|
$sortfield = $this->sortfield; |
261
|
|
|
$sortorder = $this->sortorder; |
262
|
|
|
$titleKey = $this->titleKey; |
263
|
|
|
$contextpage = $this->contextpage; |
264
|
|
|
$search = $this->search; |
265
|
|
|
$arrayfields = $this->arrayfields; |
266
|
|
|
$elementEn = $object->element; |
267
|
|
|
if ($object->element == 'commande') { |
268
|
|
|
$elementEn = 'order'; |
269
|
|
|
} elseif ($object->element == 'facture') { |
270
|
|
|
$elementEn = 'invoice'; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
// specific for invoice and remain to pay |
274
|
|
|
$discount = null; |
275
|
|
|
if ($elementEn == 'invoice') { |
276
|
|
|
$discount = new DiscountAbsolute($this->db); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
// empty value for select |
280
|
|
|
$emptyValueKey = ($elementEn == 'order' ? -5 : -1); |
281
|
|
|
|
282
|
|
|
if ($limit < 0) { |
283
|
|
|
$limit = $conf->liste_limit; |
284
|
|
|
} |
285
|
|
|
if ($page <= 0) { |
286
|
|
|
$page = 1; |
287
|
|
|
} |
288
|
|
|
$offset = $limit * ($page - 1); |
289
|
|
|
if (!$sortfield) { |
290
|
|
|
reset($object->fields); // Reset is required to avoid key() to return null. |
291
|
|
|
$sortfield = 't.' . key($object->fields); // Set here default search field. By default 1st field in definition. |
292
|
|
|
} |
293
|
|
|
if (!$sortorder) { |
294
|
|
|
$sortorder = 'DESC'; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
$socid = (int) $context->logged_thirdparty->id; |
298
|
|
|
|
299
|
|
|
// Build and execute select |
300
|
|
|
// -------------------------------------------------------------------- |
301
|
|
|
$sql = "SELECT "; |
302
|
|
|
$sql .= $object->getFieldList('t'); |
303
|
|
|
$sql .= ", t.entity as element_entity"; |
304
|
|
|
// Add fields from hooks |
305
|
|
|
$parameters = array(); |
306
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
307
|
|
|
$sql .= $hookmanager->resPrint; |
308
|
|
|
$sql = preg_replace('/,\s*$/', '', $sql); |
309
|
|
|
|
310
|
|
|
$sqlfields = $sql; // $sql fields to remove for count total |
311
|
|
|
|
312
|
|
|
$sql .= " FROM " . $this->db->prefix() . $object->table_element . " as t"; |
313
|
|
|
// Add table from hooks |
314
|
|
|
$parameters = array(); |
315
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
316
|
|
|
$sql .= $hookmanager->resPrint; |
317
|
|
|
if ($object->ismultientitymanaged == 1) { |
318
|
|
|
$sql .= " WHERE t.entity IN (" . getEntity($object->element, (GETPOSTINT('search_current_entity') ? 0 : 1)) . ")"; |
319
|
|
|
} else { |
320
|
|
|
$sql .= " WHERE 1 = 1"; |
321
|
|
|
} |
322
|
|
|
// filter on logged third-party |
323
|
|
|
$sql .= " AND t.fk_soc = " . ((int) $socid); |
324
|
|
|
// discard record with status draft |
325
|
|
|
$sql .= " AND t.fk_statut <> 0"; |
326
|
|
|
|
327
|
|
|
foreach ($search as $key => $val) { |
328
|
|
|
if (array_key_exists($key, $object->fields)) { |
329
|
|
|
if (($key == 'status' || $key == 'fk_statut') && $search[$key] == $emptyValueKey) { |
330
|
|
|
continue; |
331
|
|
|
} |
332
|
|
|
$mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); |
333
|
|
|
if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { |
334
|
|
|
if ($search[$key] == "$emptyValueKey" || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) { |
335
|
|
|
$search[$key] = ''; |
336
|
|
|
} |
337
|
|
|
$mode_search = 2; |
338
|
|
|
} |
339
|
|
|
if ($search[$key] != '') { |
340
|
|
|
$sql .= natural_search("t." . $this->db->escape($key), $search[$key], (($key == 'status' || $key == 'fk_statut') ? ($search[$key] < 0 ? 1 : 2) : $mode_search)); |
341
|
|
|
} |
342
|
|
|
} else { |
343
|
|
|
if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') { |
344
|
|
|
$columnName = preg_replace('/(_dtstart|_dtend)$/', '', $key); |
345
|
|
|
if (preg_match('/^(date|timestamp|datetime)/', $object->fields[$columnName]['type'])) { |
346
|
|
|
if (preg_match('/_dtstart$/', $key)) { |
347
|
|
|
$sql .= " AND t." . $this->db->escape($columnName) . " >= '" . $this->db->idate($search[$key]) . "'"; |
348
|
|
|
} |
349
|
|
|
if (preg_match('/_dtend$/', $key)) { |
350
|
|
|
$sql .= " AND t." . $this->db->escape($columnName) . " <= '" . $this->db->idate($search[$key]) . "'"; |
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
//if ($search_all) { |
357
|
|
|
// $sql .= natural_search(array_keys($fieldstosearchall), $search_all); |
358
|
|
|
//} |
359
|
|
|
// Add where from hooks |
360
|
|
|
$parameters = array(); |
361
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
362
|
|
|
$sql .= $hookmanager->resPrint; |
363
|
|
|
|
364
|
|
|
// Count total nb of records |
365
|
|
|
$nbtotalofrecords = 0; |
366
|
|
|
if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) { |
367
|
|
|
/* The fast and low memory method to get and count full list converts the sql into a sql count */ |
368
|
|
|
$sqlforcount = preg_replace('/^' . preg_quote($sqlfields, '/') . '/', 'SELECT COUNT(*) as nbtotalofrecords', $sql); |
369
|
|
|
$sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount); |
370
|
|
|
$resql = $this->db->query($sqlforcount); |
371
|
|
|
if ($resql) { |
372
|
|
|
$objforcount = $this->db->fetch_object($resql); |
373
|
|
|
$nbtotalofrecords = (int) $objforcount->nbtotalofrecords; |
374
|
|
|
} else { |
375
|
|
|
dol_print_error($this->db); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
if ($offset > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 1 |
379
|
|
|
$page = 1; |
380
|
|
|
$offset = 0; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
$this->db->free($resql); |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
// Complete request and execute it with limit |
387
|
|
|
$sql .= $this->db->order($sortfield, $sortorder); |
388
|
|
|
if ($limit) { |
389
|
|
|
$sql .= $this->db->plimit($limit, $offset); |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
$resql = $this->db->query($sql); |
393
|
|
|
if (!$resql) { |
394
|
|
|
dol_print_error($this->db); |
395
|
|
|
return ''; |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
$num = $this->db->num_rows($resql); |
399
|
|
|
if ($limit > 0) { |
400
|
|
|
$nbpages = ceil($nbtotalofrecords / $limit); |
401
|
|
|
} |
402
|
|
|
if ($nbpages <= 0) { |
403
|
|
|
$nbpages = 1; |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
// make array[sort field => sort order] for this list |
407
|
|
|
$sortList = array(); |
408
|
|
|
$sortFieldList = explode(",", $sortfield); |
409
|
|
|
$sortOrderList = explode(",", $sortorder); |
410
|
|
|
$sortFieldIndex = 0; |
411
|
|
|
if (!empty($sortFieldList)) { |
412
|
|
|
foreach ($sortFieldList as $sortField) { |
413
|
|
|
if (isset($sortOrderList[$sortFieldIndex])) { |
414
|
|
|
$sortList[$sortField] = $sortOrderList[$sortFieldIndex]; |
415
|
|
|
} |
416
|
|
|
$sortFieldIndex++; |
417
|
|
|
} |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
$param = ''; |
421
|
|
|
$param .= '&contextpage=' . urlencode($contextpage); |
422
|
|
|
$param .= '&limit=' . $limit; |
423
|
|
|
foreach ($search as $key => $val) { |
424
|
|
|
if (is_array($search[$key])) { |
425
|
|
|
foreach ($search[$key] as $skey) { |
426
|
|
|
if ($skey != '') { |
427
|
|
|
$param .= '&search_' . $key . '[]=' . urlencode($skey); |
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
} elseif (preg_match('/(_dtstart|_dtend)$/', $key) && !empty($val)) { |
431
|
|
|
$param .= '&search_' . $key . 'month=' . (GETPOSTINT('search_' . $key . 'month')); |
432
|
|
|
$param .= '&search_' . $key . 'day=' . (GETPOSTINT('search_' . $key . 'day')); |
433
|
|
|
$param .= '&search_' . $key . 'year=' . (GETPOSTINT('search_' . $key . 'year')); |
434
|
|
|
} elseif ($search[$key] != '') { |
435
|
|
|
$param .= '&search_' . $key . '=' . urlencode($search[$key]); |
436
|
|
|
} |
437
|
|
|
} |
438
|
|
|
// Add $param from hooks |
439
|
|
|
$parameters = array(); |
440
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
441
|
|
|
$param .= $hookmanager->resPrint; |
442
|
|
|
|
443
|
|
|
$url_file = $context->getControllerUrl($context->controller); |
444
|
|
|
$html .= '<form method="POST" id="searchFormList" action="' . $url_file . '">' . "\n"; |
445
|
|
|
$html .= $context->getFormToken(); |
446
|
|
|
$html .= '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; |
447
|
|
|
$html .= '<input type="hidden" name="action" value="list">'; |
448
|
|
|
$html .= '<input type="hidden" name="sortfield" value="' . $sortfield . '">'; |
449
|
|
|
$html .= '<input type="hidden" name="sortorder" value="' . $sortorder . '">'; |
450
|
|
|
$html .= '<input type="hidden" name="page" value="' . $page . '">'; |
451
|
|
|
$html .= '<input type="hidden" name="contextpage" value="' . $contextpage . '">'; |
452
|
|
|
|
453
|
|
|
// pagination |
454
|
|
|
$pagination_param = $param . '&sortfield=' . $sortfield . '&sortorder=' . $sortorder; |
455
|
|
|
$html .= '<nav id="webportal-' . $elementEn . '-pagination">'; |
456
|
|
|
$html .= '<ul>'; |
457
|
|
|
$html .= '<li><strong>' . $langs->trans($titleKey) . '</strong> (' . $nbtotalofrecords . ')</li>'; |
458
|
|
|
$html .= '</ul>'; |
459
|
|
|
|
460
|
|
|
/* Generate pagination list */ |
461
|
|
|
$html .= static::generatePageListNav($url_file . $pagination_param, $nbpages, $page); |
462
|
|
|
|
463
|
|
|
$html .= '</nav>'; |
464
|
|
|
|
465
|
|
|
// table with search filters and column titles |
466
|
|
|
$html .= '<table id="webportal-' . $elementEn . '-list" responsive="scroll" role="grid">'; |
467
|
|
|
// title and desc for table |
468
|
|
|
//if ($titleKey != '') { |
469
|
|
|
// $html .= '<caption id="table-collapse-responsive">'; |
470
|
|
|
// $html .= $langs->trans($titleKey) . '<br/>'; |
471
|
|
|
// if ($titleDescKey != '') { |
472
|
|
|
// $html .= '<small>' . $langs->trans($titleDescKey) . '</small>'; |
473
|
|
|
// } |
474
|
|
|
// $html .= '</caption>'; |
475
|
|
|
//} |
476
|
|
|
|
477
|
|
|
$html .= '<thead>'; |
478
|
|
|
|
479
|
|
|
// Fields title search |
480
|
|
|
// -------------------------------------------------------------------- |
481
|
|
|
$html .= '<tr role="search-row">'; |
482
|
|
|
// Action column |
483
|
|
|
// if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
484
|
|
|
$html .= '<td data-col="row-checkbox" >'; |
485
|
|
|
$html .= ' <button class="btn-filter-icon btn-search-filters-icon" type="submit" name="button_search_x" value="x" aria-label="' . dol_escape_htmltag($langs->trans('Search')) . '" ></button>'; |
486
|
|
|
$html .= ' <button class="btn-filter-icon btn-remove-search-filters-icon" type="submit" name="button_removefilter_x" value="x" aria-label="' . dol_escape_htmltag($langs->trans('RemoveSearchFilters')) . '"></button>'; |
487
|
|
|
$html .= '</td>'; |
488
|
|
|
// } |
489
|
|
|
foreach ($object->fields as $key => $val) { |
490
|
|
|
if (!empty($arrayfields['t.' . $key]['checked'])) { |
491
|
|
|
$html .= '<td data-label="' . $arrayfields['t.' . $key]['label'] . '" data-col="' . dol_escape_htmltag($key) . '" >'; |
492
|
|
|
if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { |
493
|
|
|
$html .= $this->form->selectarray('search_' . $key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', ''); |
494
|
|
|
} elseif (preg_match('/^(date|timestamp|datetime)/', $val['type'])) { |
495
|
|
|
$postDateStart = GETPOST('search_' . $key . '_dtstart', 'alphanohtml'); |
496
|
|
|
$postDateEnd = GETPOST('search_' . $key . '_dtend', 'alphanohtml'); |
497
|
|
|
|
498
|
|
|
$html .= '<div class="grid">'; |
499
|
|
|
$html .= $this->form->inputDate('search_' . $key . '_dtstart', $postDateStart ? $postDateStart : '', $langs->trans('From')); |
500
|
|
|
$html .= '</div>'; |
501
|
|
|
$html .= '<div class="grid">'; |
502
|
|
|
$html .= $this->form->inputDate('search_' . $key . '_dtend', $postDateEnd ? $postDateEnd : '', $langs->trans('to')); |
503
|
|
|
$html .= '</div>'; |
504
|
|
|
} else { |
505
|
|
|
$html .= '<input type="text" name="search_' . $key . '" value="' . dol_escape_htmltag(isset($search[$key]) ? $search[$key] : '') . '">'; |
506
|
|
|
} |
507
|
|
|
$html .= '</td>'; |
508
|
|
|
} |
509
|
|
|
} |
510
|
|
|
// Fields from hook |
511
|
|
|
$parameters = array('arrayfields' => $arrayfields); |
512
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
513
|
|
|
$html .= $hookmanager->resPrint; |
514
|
|
|
// Remain to pay |
515
|
|
|
if (!empty($arrayfields['remain_to_pay']['checked'])) { |
516
|
|
|
$html .= '<td data-label="' . $arrayfields['remain_to_pay']['label'] . '">'; |
517
|
|
|
$html .= '</td>'; |
518
|
|
|
} |
519
|
|
|
// Download link |
520
|
|
|
if (!empty($arrayfields['download_link']['checked'])) { |
521
|
|
|
$html .= '<td data-label="' . $arrayfields['download_link']['label'] . '">'; |
522
|
|
|
$html .= '</td>'; |
523
|
|
|
} |
524
|
|
|
$html .= '</tr>'; |
525
|
|
|
// Signature link |
526
|
|
|
if ($elementEn == "propal" && getDolGlobalString("PROPOSAL_ALLOW_ONLINESIGN") != 0) { |
527
|
|
|
if (!empty($arrayfields['signature_link']['checked'])) { |
528
|
|
|
$html .= '<td data-label="' . $arrayfields['signature_link']['label'] . '">'; |
529
|
|
|
$html .= '</td>'; |
530
|
|
|
} |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
$totalarray = array(); |
534
|
|
|
$totalarray['nbfield'] = 0; |
535
|
|
|
|
536
|
|
|
// Fields title label |
537
|
|
|
// -------------------------------------------------------------------- |
538
|
|
|
$html .= '<tr>'; |
539
|
|
|
// Action column |
540
|
|
|
// if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
541
|
|
|
$html .= '<th data-col="row-checkbox" ></th>'; |
542
|
|
|
$totalarray['nbfield']++; |
543
|
|
|
// } |
544
|
|
|
foreach ($object->fields as $key => $val) { |
545
|
|
|
$tableKey = 't.' . $key; |
546
|
|
|
if (!empty($arrayfields[$tableKey]['checked'])) { |
547
|
|
|
$tableOrder = ''; |
548
|
|
|
if (array_key_exists($tableKey, $sortList)) { |
549
|
|
|
$tableOrder = strtolower($sortList[$tableKey]); |
550
|
|
|
} |
551
|
|
|
$url_param = $url_file . '&sortfield=' . $tableKey . '&sortorder=' . ($tableOrder == 'desc' ? 'asc' : 'desc') . $param; |
552
|
|
|
$html .= '<th data-col="' . dol_escape_htmltag($key) . '" scope="col"' . ($tableOrder != '' ? ' table-order="' . $tableOrder . '"' : '') . '>'; |
553
|
|
|
$html .= '<a href="' . $url_param . '">'; |
554
|
|
|
$html .= $langs->trans($arrayfields['t.' . $key]['label']); |
555
|
|
|
$html .= '</a>'; |
556
|
|
|
$html .= '</th>'; |
557
|
|
|
$totalarray['nbfield']++; |
558
|
|
|
} |
559
|
|
|
} |
560
|
|
|
// Remain to pay |
561
|
|
|
if (!empty($arrayfields['remain_to_pay']['checked'])) { |
562
|
|
|
$html .= '<th scope="col">'; |
563
|
|
|
$html .= $langs->trans($arrayfields['remain_to_pay']['label']); |
564
|
|
|
$html .= '</th>'; |
565
|
|
|
$totalarray['nbfield']++; |
566
|
|
|
} |
567
|
|
|
// Download link |
568
|
|
|
if (!empty($arrayfields['download_link']['checked'])) { |
569
|
|
|
$html .= '<th scope="col">'; |
570
|
|
|
$html .= $langs->trans($arrayfields['download_link']['label']); |
571
|
|
|
$html .= '</th>'; |
572
|
|
|
$totalarray['nbfield']++; |
573
|
|
|
} |
574
|
|
|
// Signature link |
575
|
|
|
if ($elementEn == "propal" && getDolGlobalString("PROPOSAL_ALLOW_ONLINESIGN") != 0) { |
576
|
|
|
if (!empty($arrayfields['signature_link']['checked'])) { |
577
|
|
|
$html .= '<th scope="col">'; |
578
|
|
|
$html .= $langs->trans($arrayfields['signature_link']['label']); |
579
|
|
|
$html .= '</th>'; |
580
|
|
|
$totalarray['nbfield']++; |
581
|
|
|
} |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
// Hook fields |
585
|
|
|
$parameters = array('arrayfields' => $arrayfields, 'sortfield' => $sortfield, 'sortorder' => $sortorder, 'totalarray' => &$totalarray); |
586
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
587
|
|
|
$html .= $hookmanager->resPrint; |
588
|
|
|
$html .= '</tr>'; |
589
|
|
|
|
590
|
|
|
$html .= '</thead>'; |
591
|
|
|
|
592
|
|
|
$html .= '<tbody>'; |
593
|
|
|
|
594
|
|
|
// Store company |
595
|
|
|
$idCompany = (int) $socid; |
596
|
|
|
if (!isset($this->companyStaticList[$socid])) { |
597
|
|
|
$companyStatic = new Societe($this->db); |
598
|
|
|
$companyStatic->fetch($idCompany); |
599
|
|
|
$this->companyStaticList[$idCompany] = $companyStatic; |
600
|
|
|
} |
601
|
|
|
$companyStatic = $this->companyStaticList[$socid]; |
602
|
|
|
|
603
|
|
|
// Loop on record |
604
|
|
|
// -------------------------------------------------------------------- |
605
|
|
|
$i = 0; |
606
|
|
|
$totalarray = [ |
607
|
|
|
'nbfield' => 0, |
608
|
|
|
'totalizable' => [], |
609
|
|
|
]; |
610
|
|
|
$imaxinloop = ($limit ? min($num, $limit) : $num); |
611
|
|
|
while ($i < $imaxinloop) { |
612
|
|
|
$obj = $this->db->fetch_object($resql); |
613
|
|
|
if (empty($obj)) { |
614
|
|
|
break; // Should not happen |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
// Store properties in $object |
618
|
|
|
$object->setVarsFromFetchObj($obj); |
619
|
|
|
|
620
|
|
|
// specific to get invoice status (depends on payment) |
621
|
|
|
$payment = -1; |
622
|
|
|
if ($elementEn == 'invoice') { |
623
|
|
|
// paid sum |
624
|
|
|
$payment = $object->getSommePaiement(); |
625
|
|
|
$totalcreditnotes = $object->getSumCreditNotesUsed(); |
626
|
|
|
$totaldeposits = $object->getSumDepositsUsed(); |
627
|
|
|
|
628
|
|
|
// remain to pay |
629
|
|
|
$totalpay = $payment + $totalcreditnotes + $totaldeposits; |
630
|
|
|
$remaintopay = price2num($object->total_ttc - $totalpay); |
631
|
|
|
if ($object->status == Facture::STATUS_CLOSED && $object->close_code == 'discount_vat') { // If invoice closed with discount for anticipated payment |
|
|
|
|
632
|
|
|
$remaintopay = 0; |
633
|
|
|
} |
634
|
|
|
if ($object->type == Facture::TYPE_CREDIT_NOTE && $obj->paye == 1 && $discount) { |
635
|
|
|
$remaincreditnote = $discount->getAvailableDiscounts($companyStatic, '', 'rc.fk_facture_source=' . $object->id); |
636
|
|
|
$remaintopay = -$remaincreditnote; |
637
|
|
|
} |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
// Show line of result |
641
|
|
|
$html .= '<tr data-rowid="' . $object->id . '">'; |
642
|
|
|
// if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { |
643
|
|
|
$html .= '<td class="nowraponall">'; |
644
|
|
|
$html .= '</td>'; |
645
|
|
|
if (!$i) { |
646
|
|
|
$totalarray['nbfield']++; |
647
|
|
|
} |
648
|
|
|
// } |
649
|
|
|
foreach ($object->fields as $key => $val) { |
650
|
|
|
if (!empty($arrayfields['t.' . $key]['checked'])) { |
651
|
|
|
$html .= '<td class="nowraponall" data-label="' . $arrayfields['t.' . $key]['label'] . '">'; |
652
|
|
|
if ($key == 'status' || $key == 'fk_statut') { |
653
|
|
|
if ($elementEn == 'invoice') { |
654
|
|
|
// specific to get invoice status (depends on payment) |
655
|
|
|
$html .= $object->getLibStatut(5, $payment); |
656
|
|
|
} else { |
657
|
|
|
$html .= $object->getLibStatut(5); |
658
|
|
|
} |
659
|
|
|
} elseif ($key == 'rowid') { |
660
|
|
|
$html .= $this->form->showOutputFieldForObject($object, $val, $key, $object->id, ''); |
661
|
|
|
} else { |
662
|
|
|
$html .= $this->form->showOutputFieldForObject($object, $val, $key, $object->$key, ''); |
663
|
|
|
} |
664
|
|
|
$html .= '</td>'; |
665
|
|
|
|
666
|
|
|
|
667
|
|
|
if (!$i) { |
668
|
|
|
$totalarray['nbfield']++; |
669
|
|
|
} |
670
|
|
|
if (!empty($val['isameasure']) && $val['isameasure'] == 1) { |
671
|
|
|
if (!$i) { |
672
|
|
|
$totalarray['pos'][$totalarray['nbfield']] = 't.' . $key; |
673
|
|
|
} |
674
|
|
|
if (!isset($totalarray['val'])) { |
675
|
|
|
$totalarray['val'] = array(); |
676
|
|
|
} |
677
|
|
|
if (!isset($totalarray['val']['t.' . $key])) { |
678
|
|
|
$totalarray['val']['t.' . $key] = 0; |
679
|
|
|
} |
680
|
|
|
$totalarray['val']['t.' . $key] += $object->$key; |
681
|
|
|
} |
682
|
|
|
} |
683
|
|
|
} |
684
|
|
|
// Remain to pay |
685
|
|
|
if (!empty($arrayfields['remain_to_pay']['checked'])) { |
686
|
|
|
$html .= '<td class="nowraponall" data-label="' . $arrayfields['remain_to_pay']['label'] . '">'; |
687
|
|
|
$html .= $this->form->showOutputFieldForObject($object, $arrayfields['remain_to_pay'], 'remain_to_pay', $remaintopay, ''); |
688
|
|
|
//$html .= price($remaintopay); |
689
|
|
|
$html .= '</td>'; |
690
|
|
|
if (!$i) { |
691
|
|
|
$totalarray['nbfield']++; |
692
|
|
|
} |
693
|
|
|
} |
694
|
|
|
// Download link |
695
|
|
|
if (!empty($arrayfields['download_link']['checked'])) { |
696
|
|
|
$element = $object->element; |
697
|
|
|
$html .= '<td class="nowraponall" data-label="' . $arrayfields['download_link']['label'] . '">'; |
698
|
|
|
$filename = dol_sanitizeFileName($obj->ref); |
699
|
|
|
$filedir = $conf->{$element}->multidir_output[$obj->element_entity] . '/' . dol_sanitizeFileName($obj->ref); |
700
|
|
|
$html .= $this->form->getDocumentsLink($element, $filename, $filedir); |
701
|
|
|
$html .= '</td>'; |
702
|
|
|
if (!$i) { |
703
|
|
|
$totalarray['nbfield']++; |
704
|
|
|
} |
705
|
|
|
} |
706
|
|
|
// Signature link |
707
|
|
|
if ($elementEn == "propal" && getDolGlobalString("PROPOSAL_ALLOW_ONLINESIGN") != 0) { |
708
|
|
|
if (!empty($arrayfields['signature_link']['checked'])) { |
709
|
|
|
$html .= '<td class="nowraponall" data-label="' . $arrayfields['signature_link']['label'] . '">'; |
710
|
|
|
if ($object->fk_statut == Propal::STATUS_VALIDATED) { |
711
|
|
|
$html .= $this->form->getSignatureLink('proposal', $object); |
712
|
|
|
} |
713
|
|
|
$html .= '</td>'; |
714
|
|
|
if (!$i) { |
715
|
|
|
$totalarray['nbfield']++; |
716
|
|
|
} |
717
|
|
|
} |
718
|
|
|
} |
719
|
|
|
// Fields from hook |
720
|
|
|
$parameters = array('arrayfields' => $arrayfields, 'object' => $object, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray); |
721
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
722
|
|
|
$html .= $hookmanager->resPrint; |
723
|
|
|
|
724
|
|
|
$html .= '</tr>'; |
725
|
|
|
|
726
|
|
|
$i++; |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
// Move fields of totalizable into the common array pos and val |
730
|
|
|
if (!empty($totalarray['totalizable']) && is_array($totalarray['totalizable'])) { |
731
|
|
|
foreach ($totalarray['totalizable'] as $keytotalizable => $valtotalizable) { |
732
|
|
|
$totalarray['pos'][$valtotalizable['pos']] = $keytotalizable; |
733
|
|
|
$totalarray['val'][$keytotalizable] = isset($valtotalizable['total']) ? $valtotalizable['total'] : 0; |
734
|
|
|
} |
735
|
|
|
} |
736
|
|
|
// Show total line |
737
|
|
|
if (isset($totalarray['pos'])) { |
738
|
|
|
$html .= '<tr>'; |
739
|
|
|
$i = 0; |
740
|
|
|
while ($i < $totalarray['nbfield']) { |
741
|
|
|
$i++; |
742
|
|
|
if (!empty($totalarray['pos'][$i])) { |
743
|
|
|
$html .= '<td class="nowraponall essai">'; |
744
|
|
|
$html .= price(!empty($totalarray['val'][$totalarray['pos'][$i]]) ? $totalarray['val'][$totalarray['pos'][$i]] : 0); |
745
|
|
|
$html .= '</td>'; |
746
|
|
|
} else { |
747
|
|
|
if ($i == 1) { |
748
|
|
|
$html .= '<td>' . $langs->trans("Total") . '</td>'; |
749
|
|
|
} else { |
750
|
|
|
$html .= '<td></td>'; |
751
|
|
|
} |
752
|
|
|
} |
753
|
|
|
} |
754
|
|
|
$html .= '</tr>'; |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
// If no record found |
758
|
|
|
if ($num == 0) { |
759
|
|
|
$colspan = 1; |
760
|
|
|
foreach ($arrayfields as $key => $val) { |
761
|
|
|
if (!empty($val['checked'])) { |
762
|
|
|
$colspan++; |
763
|
|
|
} |
764
|
|
|
} |
765
|
|
|
$html .= '<tr><td colspan="' . $colspan . '"><span class="opacitymedium">' . $langs->trans("NoRecordFound") . '</span></td></tr>'; |
766
|
|
|
} |
767
|
|
|
|
768
|
|
|
$html .= '</tbody>'; |
769
|
|
|
|
770
|
|
|
$this->db->free($resql); |
771
|
|
|
|
772
|
|
|
$parameters = array('arrayfields' => $arrayfields, 'sql' => $sql); |
773
|
|
|
$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook |
774
|
|
|
$html .= $hookmanager->resPrint; |
775
|
|
|
|
776
|
|
|
$html .= '</table>'; |
777
|
|
|
|
778
|
|
|
$html .= '</form>'; |
779
|
|
|
|
780
|
|
|
return $html; |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
/** |
784
|
|
|
* Generate with pagination navigaion |
785
|
|
|
* |
786
|
|
|
* @param string $url Url of current page |
787
|
|
|
* @param int $nbPages Total of pages results |
788
|
|
|
* @param int $currentPage Number of current page |
789
|
|
|
* @return string |
790
|
|
|
*/ |
791
|
|
|
public static function generatePageListNav(string $url, int $nbPages, int $currentPage) |
792
|
|
|
{ |
793
|
|
|
global $langs; |
794
|
|
|
|
795
|
|
|
// Return nothing (no navigation bar), if there is only 1 page. |
796
|
|
|
if ($nbPages <= 1) { |
797
|
|
|
return ''; |
798
|
|
|
} |
799
|
|
|
|
800
|
|
|
$pSep = strpos($url, '?') === false ? '?' : '&'; |
801
|
|
|
|
802
|
|
|
$html = '<ul class="pages-nav-list">'; |
803
|
|
|
|
804
|
|
|
if ($currentPage > 1) { |
805
|
|
|
$html .= '<li><a class="pages-nav-list__icon --prev" aria-label="' . dol_escape_htmltag($langs->trans('AriaPrevPage')) . '" href="' . $url . $pSep . 'page=' . ($currentPage - 1) . '" ' . ($currentPage <= 1 ? ' disabled' : '') . '></a></li>'; |
806
|
|
|
} |
807
|
|
|
|
808
|
|
|
$maxPaginItem = min($nbPages, 5); |
809
|
|
|
$minPageNum = max(1, $currentPage - 3); |
810
|
|
|
$maxPageNum = min($nbPages, $currentPage + 3); |
811
|
|
|
|
812
|
|
|
if ($minPageNum > 1) { |
813
|
|
|
$html .= '<li><a class="pages-nav-list__link ' . ($currentPage == 1 ? '--active' : '') . '" aria-label="' . dol_escape_htmltag($langs->trans('AriaPageX', 1)) . '" href="' . $url . $pSep . 'page=1" >1</a></li>'; |
814
|
|
|
$html .= '<li>…</li>'; |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
for ($p = $minPageNum; $p <= $maxPageNum; $p++) { |
818
|
|
|
$html .= '<li><a class="pages-nav-list__link ' . ($currentPage === $p ? '--active' : '') . '" aria-label="' . dol_escape_htmltag($langs->trans('AriaPageX', $p)) . '" href="' . $url . $pSep . 'page=' . $p . '">' . $p . '</a></li>'; |
819
|
|
|
} |
820
|
|
|
|
821
|
|
|
if ($maxPaginItem < $nbPages) { |
822
|
|
|
$html .= '<li>…</li>'; |
823
|
|
|
$html .= '<li><a class="pages-nav-list__link ' . ($currentPage == $nbPages ? '--active' : '') . '" aria-label="' . dol_escape_htmltag($langs->trans('AriaPageX', $nbPages)) . '" href="' . $url . $pSep . 'page=' . $nbPages . '">' . $nbPages . '</a></li>'; |
824
|
|
|
} |
825
|
|
|
|
826
|
|
|
if ($currentPage < $nbPages) { |
827
|
|
|
$html .= '<li><a class="pages-nav-list__icon --next" aria-label="' . dol_escape_htmltag($langs->trans('AriaNextPage')) . '" href="' . $url . $pSep . 'page=' . ($currentPage + 1) . '" ' . ($currentPage >= $nbPages ? ' disabled' : '') . '></a></li>'; |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
$html .= '</ul>'; |
831
|
|
|
|
832
|
|
|
return $html; |
833
|
|
|
} |
834
|
|
|
} |
835
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.