dolibarr 25.0.0-alpha
ajaxextrafield.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2007-2024 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
26if (!defined('NOTOKENRENEWAL')) {
27 // Disables token renewal
28 define('NOTOKENRENEWAL', 1);
29}
30if (!defined('NOREQUIREMENU')) {
31 define('NOREQUIREMENU', '1');
32}
33if (!defined('NOREQUIREHTML')) {
34 define('NOREQUIREHTML', '1');
35}
36if (!defined('NOREQUIREAJAX')) {
37 define('NOREQUIREAJAX', '1');
38}
39if (!defined('NOHEADERNOFOOTER')) {
40 define('NOHEADERNOFOOTER', '1');
41}
42
43include '../../main.inc.php';
50include_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
51
52// object id
53$objectid = GETPOST('objectid', 'aZ09');
54// 'module' or 'myobject@mymodule', 'mymodule_myobject'
55$objecttype = GETPOST('objecttype', 'aZ09arobase');
56$objectkey = GETPOST('objectkey', 'restricthtml');
57$search = GETPOST('search', 'restricthtml');
58$page = GETPOSTINT('page');
59$mode = GETPOST('mode', 'aZ09');
60$value = GETPOST('value', 'alphanohtml');
61$limit = 10;
62$offset = (($page - 1) * $limit);
63$element_ref = '';
64if (is_numeric($objectid)) {
65 $objectid = (int) $objectid;
66} else {
67 $element_ref = $objectid;
68 $objectid = 0;
69}
70// Load object according to $element
71$object = fetchObjectByElement($objectid, $objecttype, $element_ref);
72if (empty($object->element)) {
73 httponly_accessforbidden('Failed to get object with fetchObjectByElement(id=' . $objectid . ', objecttype=' . $objecttype . ')');
74}
75
76$module = $object->module;
77$element = $object->element;
78
79$usesublevelpermission = ($module != $element ? $element : '');
80if ($usesublevelpermission && !$user->hasRight($module, $element)) { // There is no permission on object defined, we will check permission on module directly
81 $usesublevelpermission = '';
82}
83
84// print $object->id.' - '.$object->module.' - '.$object->element.' - '.$object->table_element.' - '.$usesublevelpermission."\n";
85
86// Security check
87restrictedArea($user, $object->module, $object, $object->table_element, $usesublevelpermission);
88
89
90/*
91 * View
92 */
93
95
96$data = [
97 'results' => [],
98 'pagination' => [
99 'more' => true,
100 ]
101];
102if ($page == 1) {
103 $data['results'][] = [
104 'id' => -1,
105 'text' => '&nbsp;',
106 ];
107}
108$i = 0;
109if ($object instanceof CommonObject) {
110 $extrafields = new ExtraFields($db);
111 $extrafields->fetch_name_optionals_label($element);
112 $options = $extrafields->attributes[$element]['param'][$objectkey]['options'];
113 if (is_array($options)) {
114 // WARNING!! @FIXME This code is duplicated into core/class/extrafields.class.php
115
116 $tmpparamoptions = array_keys($options);
117 $paramoptions = preg_split('/[\r\n]+/', $tmpparamoptions[0]);
118
119 $InfoFieldList = explode(":", $paramoptions[0], 5);
120 // 0 : tableName
121 // 1 : label field name
122 // 2 : key fields name (if different of rowid)
123 // optional parameters...
124 // 3 : key field parent (for dependent lists). How this is used ?
125 // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value. Or use USF on the second line.
126 // 5 : string category type. This replace the filter.
127 // 6 : ids categories list separated by comma for category root. This replace the filter.
128 // 7 : sort field (not used here but used into format for commobject)
129
130 // If there is a filter, we extract it by taking all content inside parenthesis.
131 if (! empty($InfoFieldList[4])) {
132 $pos = 0; // $pos will be position of ending filter
133 $parenthesisopen = 0;
134 while (substr($InfoFieldList[4], $pos, 1) !== '' && ($parenthesisopen || $pos == 0 || substr($InfoFieldList[4], $pos, 1) != ':')) {
135 if (substr($InfoFieldList[4], $pos, 1) == '(') {
136 $parenthesisopen++;
137 }
138 if (substr($InfoFieldList[4], $pos, 1) == ')') {
139 $parenthesisopen--;
140 }
141 $pos++;
142 }
143 $tmpbefore = substr($InfoFieldList[4], 0, $pos);
144 $tmpafter = substr($InfoFieldList[4], $pos + 1);
145 //var_dump($InfoFieldList[4].' -> '.$pos); var_dump($tmpafter);
146 $InfoFieldList[4] = $tmpbefore;
147 if ($tmpafter !== '') {
148 $InfoFieldList = array_merge($InfoFieldList, explode(':', $tmpafter));
149 }
150
151 // Fix better compatibility with some old extrafield syntax filter "(field=123)"
152 $reg = array();
153 if (preg_match('/^\‍(?([a-z0-9]+)([=<>]+)(\d+)\‍)?$/i', $InfoFieldList[4], $reg)) {
154 $InfoFieldList[4] = '(' . $reg[1] . ':' . $reg[2] . ':' . $reg[3] . ')';
155 }
156
157 //var_dump($InfoFieldList);
158 }
159
160 $parentName = '';
161 $parentField = '';
162 $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
163
164 if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
165 list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
166 $keyList .= ', ' . $parentField;
167 }
168 if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
169 if (strpos($InfoFieldList[4], 'extra.') !== false) {
170 $keyList = 'main.' . $db->sanitize($InfoFieldList[2]) . ' as rowid';
171 } else {
172 $keyList = $db->sanitize($InfoFieldList[2]) . ' as rowid';
173 }
174 }
175
176 $filter_categorie = false;
177 if (count($InfoFieldList) > 5) {
178 if ($InfoFieldList[0] == 'categorie') {
179 $filter_categorie = true;
180 }
181 }
182
183 if (!$filter_categorie) {
184 $fields_label = isset($InfoFieldList[1]) ? explode('|', $InfoFieldList[1]) : array();
185 if (!empty($fields_label)) {
186 $keyList .= ', ';
187 $keyList .= implode(', ', $fields_label);
188 }
189
190 $sqlwhere = '';
191 $sql = "SELECT " . $db->sanitize($keyList, 0, 0, 1);
192 $sql .= ' FROM ' . $db->prefix() . $db->sanitize($InfoFieldList[0]);
193
194 // Add filter from 4th field
195 if (!empty($InfoFieldList[4])) {
196 // can use current entity filter
197 if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
198 $InfoFieldList[4] = str_replace('$ENTITY$', (string) $conf->entity, $InfoFieldList[4]);
199 }
200 // can use SELECT sub request
201 global $dolibarr_allow_unsecured_select_in_extrafields_filter;
202 if (!empty($dolibarr_allow_unsecured_select_in_extrafields_filter)) {
203 if (strpos($InfoFieldList[4], '$SEL$') !== false) {
204 $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
205 }
206 }
207 // can use MODE parameter (list or view)
208 if (strpos($InfoFieldList[4], '$MODE$') !== false) {
209 $InfoFieldList[4] = str_replace('$MODE$', preg_replace('/[^a-z0-9_]/i', '', (string) $mode), $InfoFieldList[4]);
210 }
211
212 // current object id can be use into filter
213 if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
214 $InfoFieldList[4] = str_replace('$ID$', (string) $objectid, $InfoFieldList[4]);
215 } else {
216 $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
217 }
218
219 // can filter on any field of object
220 //if (is_object($object)) {
221 $tags = [];
222 preg_match_all('/\$(.*?)\$/', $InfoFieldList[4], $tags);
223 foreach ($tags[0] as $keytag => $valuetag) {
224 $property = preg_replace('/[^a-z0-9_]/', '', strtolower($tags[1][$keytag]));
225 if (strpos($InfoFieldList[4], $valuetag) !== false && property_exists($object, $property) && !empty($object->$property)) {
226 $InfoFieldList[4] = str_replace($valuetag, (string) $object->$property, $InfoFieldList[4]);
227 } else {
228 $InfoFieldList[4] = str_replace($valuetag, '0', $InfoFieldList[4]);
229 }
230 }
231 //}
232
233 // We have to filter on a field of the extrafield table
234 $errstr = '';
235 if (strpos($InfoFieldList[4], 'extra.') !== false) {
236 $sql .= ' as main, ' . $db->sanitize($db->prefix() . $InfoFieldList[0]) . '_extrafields as extra'; // Add the join
237 $sqlwhere .= " WHERE extra.fk_object = main." . $db->sanitize($InfoFieldList[2]);
238 $sqlwhere .= " AND " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1); // Add the filter
239 } else {
240 $sqlwhere .= " WHERE " . forgeSQLFromUniversalSearchCriteria($InfoFieldList[4], $errstr, 1);
241 }
242 } else {
243 $sqlwhere .= ' WHERE 1=1';
244 }
245
246 // Some tables may have field, some other not. For the moment we disable it.
247 if (in_array($InfoFieldList[0], array('tablewithentity'))) {
248 $sqlwhere .= ' AND entity = ' . ((int) $conf->entity);
249 }
250 if ($search) {
251 if ($fields_label) {
252 $sqlwhere .= " " . natural_search($fields_label, $search, 0);
253 }
254 }
255
256 $sql .= $sqlwhere;
257
258 $orderfields = explode('|', $InfoFieldList[1]);
259 $keyList = $InfoFieldList[1];
260 if (count($orderfields)) {
261 $keyList = implode(', ', $orderfields);
262 }
263 $sql .= $db->order($keyList);
264 $sql .= $db->plimit($limit, $offset);
265
266 $data['sql'] = $sql;
267
268 $resql = $db->query($sql);
269 if ($resql) {
270 // $out .= '<option value="0">&nbsp;</option>';
271 $num = $db->num_rows($resql);
272 $i = 0;
273 while ($i < $num) {
274 $labeltoshow = '';
275 $obj = $db->fetch_object($resql);
276
277 // Several field into label (eq table:code|label:rowid)
278 $notrans = false;
279 $fields_label = explode('|', $InfoFieldList[1]);
280 if (count($fields_label) > 1) {
281 $notrans = true;
282 foreach ($fields_label as $field_toshow) {
283 $labeltoshow .= $obj->$field_toshow . ' ';
284 }
285 } else {
286 $labeltoshow = $obj->{$InfoFieldList[1]};
287 }
288
289 if ($value == $obj->rowid) {
290 if (!$notrans) {
291 foreach ($fields_label as $field_toshow) {
292 $translabel = $langs->trans($obj->$field_toshow);
293 $labeltoshow = $translabel . ' ';
294 }
295 }
296 // $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
297 $data['results'][] = [
298 'id' => $obj->rowid,
299 'text' => $labeltoshow,
300 ];
301 } else {
302 if (!$notrans) {
303 $translabel = $langs->trans($obj->{$InfoFieldList[1]});
304 $labeltoshow = $translabel;
305 }
306 if (empty($labeltoshow)) {
307 $labeltoshow = '(not defined)';
308 }
309
310 /*
311 if (!empty($InfoFieldList[3]) && $parentField) {
312 $parent = $parentName . ':' . $obj->{$parentField};
313 }
314
315 $out .= '<option value="'.$obj->rowid.'"';
316 $out .= ($value == $obj->rowid ? ' selected' : '');
317 $out .= (!empty($parent) ? ' data-parent="'.$parent.'"' : '');
318 $out .= '>'.$labeltoshow.'</option>';
319 */
320 $data['results'][] = [
321 'id' => $obj->rowid,
322 'text' => $labeltoshow,
323 ];
324 }
325
326 $i++;
327 }
328 $db->free($resql);
329 } else {
330 dol_syslog('Error in request ' . $db->lasterror() . '. Check setup of extra parameters.', LOG_ERR);
331 }
332 } else {
333 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
334 require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
335 }
336 }
337}
338
339if ($page > 1 && $i < 9) {
340 $data['pagination'] = [
341 'more' => false,
342 ];
343}
344print json_encode($data);
345
346$db->close();
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage standard extra fields.
if(! $sortfield) if(! $sortorder) $module
Definition list.php:193
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
natural_search($fields, $value, $mode=0, $nofirstand=0, $sqltoadd='')
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0, $forbiddenfields=array())
forgeSQLFromUniversalSearchCriteria
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
httponly_accessforbidden($message='1', $http_response_code=403, $stringalreadysanitized=0)
Show a message to say access is forbidden and stop program.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.