Passed
Push — EXTRACT_CLASSES ( 231cec )
by Rafael
70:48
created

DolibarrApi::_checkValForAPI()   D

Complexity

Conditions 18
Paths 38

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 22
nc 38
nop 3
dl 0
loc 43
rs 4.8666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2015       Jean-François Ferry         <[email protected]>
4
 * Copyright (C) 2016	    Laurent Destailleur		    <[email protected]>
5
 * Copyright (C) 2020		Frédéric France		        <[email protected]>
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
namespace Dolibarr\Core\Base;
24
25
use Luracast\Restler\Defaults;
26
use Luracast\Restler\Restler;
27
28
require_once constant('DOL_DOCUMENT_ROOT') . '/user/class/user.class.php';
29
30
/**
31
 * Class for API REST v1
32
 */
33
class DolibarrApi
34
{
35
    /**
36
     * @var Restler $r Restler object
37
     */
38
    public $r;
39
    /**
40
     * @var DoliDB $db Database object
0 ignored issues
show
Bug introduced by
The type Dolibarr\Core\Base\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
41
     */
42
    protected $db;
43
44
    /**
45
     * Constructor
46
     *
47
     * @param DoliDB $db Database handler
48
     * @param string $cachedir Cache dir
49
     * @param boolean $refreshCache Update cache
50
     */
51
    public function __construct($db, $cachedir = '', $refreshCache = false)
52
    {
53
        global $conf, $dolibarr_main_url_root;
54
55
        if (empty($cachedir)) {
56
            $cachedir = $conf->api->dir_temp;
57
        }
58
        Defaults::$cacheDirectory = $cachedir;
59
60
        $this->db = $db;
61
        $production_mode = (!getDolGlobalString('API_PRODUCTION_MODE') ? false : true);
62
        $this->r = new Restler($production_mode, $refreshCache);
63
64
        $urlwithouturlroot = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim($dolibarr_main_url_root));
65
        $urlwithroot = $urlwithouturlroot . DOL_URL_ROOT; // This is to use external domain name found into config file
66
67
        $urlwithouturlrootautodetect = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim(DOL_MAIN_URL_ROOT));
68
        $urlwithrootautodetect = $urlwithouturlroot . DOL_URL_ROOT; // This is to use local domain autodetected by dolibarr from url
69
70
        $this->r->setBaseUrls($urlwithouturlroot, $urlwithouturlrootautodetect);
71
        $this->r->setAPIVersion(1);
72
        //$this->r->setSupportedFormats('json');
73
        //$this->r->setSupportedFormats('jsonFormat');
74
    }
75
76
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
77
78
    /**
79
     * Check access by user to a given resource
80
     *
81
     * @param string $resource element to check
82
     * @param int $resource_id Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
83
     * @param string $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity. Not used if objectid is null (optional)
84
     * @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
85
     * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
86
     * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional)
87
     * @return bool
88
     */
89
    protected static function _checkAccessToResource($resource, $resource_id = 0, $dbtablename = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid')
90
    {
91
        // phpcs:enable
92
        // Features/modules to check
93
        $featuresarray = array($resource);
94
        if (preg_match('/&/', $resource)) {
95
            $featuresarray = explode("&", $resource);
96
        } elseif (preg_match('/\|/', $resource)) {
97
            $featuresarray = explode("|", $resource);
98
        }
99
100
        // More subfeatures to check
101
        if (!empty($feature2)) {
102
            $feature2 = explode("|", $feature2);
103
        }
104
105
        return checkUserAccessToObject(DolibarrApiAccess::$user, $featuresarray, $resource_id, $dbtablename, $feature2, $dbt_keyfield, $dbt_select);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Core\Base\DolibarrApiAccess was not found. Did you mean DolibarrApiAccess? If so, make sure to prefix the type with \.
Loading history...
106
    }
107
108
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
109
110
    /**
111
     * Function to forge a SQL criteria from a Generic filter string.
112
     * Function no more used. Kept for backward compatibility with old APIs of modules
113
     *
114
     * @param array $matches Array of found string by regex search.
115
     *                              Each entry is 1 and only 1 criteria.
116
     *                              Example: "t.ref:like:'SO-%'", "t.date_creation:<:'20160101'", "t.date_creation:<:'2016-01-01 12:30:00'", "t.nature:is:NULL", "t.field2:isnot:NULL"
117
     * @return string               Forged criteria. Example: "t.field like 'abc%'"
118
     */
119
    protected static function _forge_criteria_callback($matches)
120
    {
121
        return dolForgeCriteriaCallback($matches);
122
    }
123
124
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
125
126
    /**
127
     * Check and convert a string depending on its type/name.
128
     *
129
     * @param string $field Field name
130
     * @param string|array $value Value to check/clean
131
     * @param Object $object Object
132
     * @return  string|array                Value cleaned
133
     */
134
    protected function _checkValForAPI($field, $value, $object)
135
    {
136
        // phpcs:enable
137
        if (!is_array($value)) {
138
            // Sanitize the value using its type declared into ->fields of $object
139
            if (!empty($object->fields) && !empty($object->fields[$field]) && !empty($object->fields[$field]['type'])) {
140
                if (strpos($object->fields[$field]['type'], 'int') || strpos($object->fields[$field]['type'], 'double') || in_array($object->fields[$field]['type'], array('real', 'price', 'stock'))) {
141
                    return sanitizeVal($value, 'int');
142
                }
143
                if ($object->fields[$field]['type'] == 'html') {
144
                    return sanitizeVal($value, 'restricthtml');
145
                }
146
                if ($object->fields[$field]['type'] == 'select') {
147
                    // Check values are in the list of possible 'options'
148
                    // TODO
149
                }
150
                if ($object->fields[$field]['type'] == 'sellist' || $object->fields[$field]['type'] == 'checkbox') {
151
                    // TODO
152
                }
153
                if ($object->fields[$field]['type'] == 'boolean' || $object->fields[$field]['type'] == 'radio') {
154
                    // TODO
155
                }
156
                if ($object->fields[$field]['type'] == 'email') {
157
                    return sanitizeVal($value, 'email');
158
                }
159
                if ($object->fields[$field]['type'] == 'password') {
160
                    return sanitizeVal($value, 'none');
161
                }
162
                // Others will use 'alphanohtml'
163
            }
164
165
            if (in_array($field, array('note', 'note_private', 'note_public', 'desc', 'description'))) {
166
                return sanitizeVal($value, 'restricthtml');
167
            } else {
168
                return sanitizeVal($value, 'alphanohtml');
169
            }
170
        } else {    // Example when $field = 'extrafields' and $value = content of $object->array_options
171
            $newarrayvalue = array();
172
            foreach ($value as $tmpkey => $tmpvalue) {
173
                $newarrayvalue[$tmpkey] = $this->_checkValForAPI($tmpkey, $tmpvalue, $object);
174
            }
175
176
            return $newarrayvalue;
177
        }
178
    }
179
180
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
181
182
    /**
183
     * Filter properties that will be returned on object
184
     *
185
     * @param Object $object Object to clean
186
     * @param String $properties Comma separated list of properties names
187
     * @return  Object                  Object with cleaned properties
188
     */
189
    protected function _filterObjectProperties($object, $properties)
190
    {
191
        // phpcs:enable
192
        // If properties is empty, we return all properties
193
        if (empty($properties)) {
194
            return $object;
195
        }
196
197
        // Copy of exploded array for efficiency
198
        $arr_properties = explode(',', $properties);
199
        $magic_properties = array();
200
        $real_properties = get_object_vars($object);
201
202
        // Unsetting real properties may unset magic properties.
203
        // We keep a copy of the requested magic properties
204
        foreach ($arr_properties as $key) {
205
            if (!array_key_exists($key, $real_properties)) {
206
                // Not a real property,
207
                // check if $key is a magic property (we want to keep '$obj->$key')
208
                if (property_exists($object, $key) && isset($object->$key)) {
209
                    $magic_properties[$key] = $object->$key;
210
                }
211
            }
212
        }
213
214
        // Filter real properties (may indirectly unset magic properties)
215
        foreach (get_object_vars($object) as $key => $value) {
216
            if (!in_array($key, $arr_properties)) {
217
                unset($object->$key);
218
            }
219
        }
220
221
        // Restore the magic properties
222
        foreach ($magic_properties as $key => $value) {
223
            $object->$key = $value;
224
        }
225
226
        return $object;
227
    }
228
229
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
230
231
    /**
232
     * Clean sensible object datas
233
     *
234
     * @param Object $object Object to clean
235
     * @return  Object              Object with cleaned properties
236
     */
237
    protected function _cleanObjectDatas($object)
238
    {
239
        // phpcs:enable
240
        // Remove $db object property for object
241
        unset($object->db);
242
        unset($object->isextrafieldmanaged);
243
        unset($object->ismultientitymanaged);
244
        unset($object->restrictiononfksoc);
245
        unset($object->table_rowid);
246
        unset($object->pass);
247
        unset($object->pass_indatabase);
248
249
        // Remove linkedObjects. We should already have and keep only linkedObjectsIds that avoid huge responses
250
        unset($object->linkedObjects);
251
        //unset($object->lines[$i]->linked_objects);        // This is the array to create linked object during create
252
253
        unset($object->fields);
254
        unset($object->oldline);
255
256
        unset($object->error);
257
        unset($object->errors);
258
        unset($object->errorhidden);
259
260
        unset($object->ref_previous);
261
        unset($object->ref_next);
262
        unset($object->imgWidth);
263
        unset($object->imgHeight);
264
        unset($object->barcode_type_code);
265
        unset($object->barcode_type_label);
266
267
        unset($object->mode_reglement);     // We use mode_reglement_id now
268
        unset($object->cond_reglement);     // We use cond_reglement_id now
269
        unset($object->note);               // We use note_public or note_private now
270
        unset($object->contact);            // We use contact_id now
271
        unset($object->thirdparty);         // We use thirdparty_id or fk_soc or socid now
272
273
        unset($object->projet); // Should be fk_project
274
        unset($object->project); // Should be fk_project
275
        unset($object->fk_projet); // Should be fk_project
276
        unset($object->author); // Should be fk_user_author
277
        unset($object->timespent_old_duration);
278
        unset($object->timespent_id);
279
        unset($object->timespent_duration);
280
        unset($object->timespent_date);
281
        unset($object->timespent_datehour);
282
        unset($object->timespent_withhour);
283
        unset($object->timespent_fk_user);
284
        unset($object->timespent_note);
285
        unset($object->fk_delivery_address);
286
        unset($object->model_pdf);
287
        unset($object->sendtoid);
288
        unset($object->name_bis);
289
        unset($object->newref);
290
        unset($object->oldref);
291
        unset($object->alreadypaid);
292
        unset($object->openid);
293
        unset($object->fk_bank);
294
        unset($object->showphoto_on_popup);
295
        unset($object->nb);
296
        unset($object->nbphoto);
297
        unset($object->output);
298
        unset($object->tpl);
299
        //unset($object->libelle);
300
301
        unset($object->stats_propale);
302
        unset($object->stats_commande);
303
        unset($object->stats_contrat);
304
        unset($object->stats_facture);
305
        unset($object->stats_commande_fournisseur);
306
        unset($object->stats_reception);
307
        unset($object->stats_mrptoconsume);
308
        unset($object->stats_mrptoproduce);
309
310
        unset($object->origin_object);
311
        unset($object->origin);
312
        unset($object->element);
313
        unset($object->element_for_permission);
314
        unset($object->fk_element);
315
        unset($object->table_element);
316
        unset($object->table_element_line);
317
        unset($object->class_element_line);
318
        unset($object->picto);
319
        unset($object->linked_objects);
320
321
        unset($object->fieldsforcombobox);
322
        unset($object->regeximgext);
323
324
        unset($object->skip_update_total);
325
        unset($object->context);
326
        unset($object->next_prev_filter);
327
328
        unset($object->region);
329
        unset($object->region_code);
330
        unset($object->country);
331
        unset($object->state);
332
        unset($object->state_code);
333
        unset($object->fk_departement);
334
        unset($object->departement);
335
        unset($object->departement_code);
336
337
        unset($object->libelle_statut);
338
        unset($object->libelle_paiement);
339
        unset($object->labelStatus);
340
        unset($object->labelStatusShort);
341
342
        unset($object->actionmsg);
343
        unset($object->actionmsg2);
344
345
        unset($object->prefix_comm);
346
347
        if (!isset($object->table_element) || $object->table_element != 'ticket') {
348
            unset($object->comments);
349
        }
350
351
        // Remove the $oldcopy property because it is not supported by the JSON
352
        // encoder. The following error is generated when trying to serialize
353
        // it: "Error encoding/decoding JSON: Type is not supported"
354
        // Note: Event if this property was correctly handled by the JSON
355
        // encoder, it should be ignored because keeping it would let the API
356
        // have a very strange behavior: calling PUT and then GET on the same
357
        // resource would give different results:
358
        // PUT /objects/{id} -> returns object with oldcopy = previous version of the object
359
        // GET /objects/{id} -> returns object with oldcopy empty
360
        unset($object->oldcopy);
361
362
        // If object has lines, remove $db property
363
        if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
364
            $nboflines = count($object->lines);
365
            for ($i = 0; $i < $nboflines; $i++) {
366
                $this->_cleanObjectDatas($object->lines[$i]);
367
368
                unset($object->lines[$i]->contact);
369
                unset($object->lines[$i]->contact_id);
370
                unset($object->lines[$i]->country);
371
                unset($object->lines[$i]->country_id);
372
                unset($object->lines[$i]->country_code);
373
                unset($object->lines[$i]->mode_reglement_id);
374
                unset($object->lines[$i]->mode_reglement_code);
375
                unset($object->lines[$i]->mode_reglement);
376
                unset($object->lines[$i]->cond_reglement_id);
377
                unset($object->lines[$i]->cond_reglement_code);
378
                unset($object->lines[$i]->cond_reglement);
379
                unset($object->lines[$i]->fk_delivery_address);
380
                unset($object->lines[$i]->fk_projet);
381
                unset($object->lines[$i]->fk_project);
382
                unset($object->lines[$i]->thirdparty);
383
                unset($object->lines[$i]->user);
384
                unset($object->lines[$i]->model_pdf);
385
                unset($object->lines[$i]->note_public);
386
                unset($object->lines[$i]->note_private);
387
                unset($object->lines[$i]->fk_incoterms);
388
                unset($object->lines[$i]->label_incoterms);
389
                unset($object->lines[$i]->location_incoterms);
390
                unset($object->lines[$i]->name);
391
                unset($object->lines[$i]->lastname);
392
                unset($object->lines[$i]->firstname);
393
                unset($object->lines[$i]->civility_id);
394
                unset($object->lines[$i]->fk_multicurrency);
395
                unset($object->lines[$i]->multicurrency_code);
396
                unset($object->lines[$i]->shipping_method_id);
397
            }
398
        }
399
400
        if (!empty($object->thirdparty) && is_object($object->thirdparty)) {
401
            $this->_cleanObjectDatas($object->thirdparty);
402
        }
403
404
        if (!empty($object->product) && is_object($object->product)) {
405
            $this->_cleanObjectDatas($object->product);
406
        }
407
408
        return $object;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $object also could return the type object which is incompatible with the documented return type object.
Loading history...
409
    }
410
411
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
412
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
413
414
    /**
415
     * Return if a $sqlfilters parameter is valid
416
     * Function no more used. Kept for backward compatibility with old APIs of modules
417
     *
418
     * @param string $sqlfilters sqlfilter string
419
     * @param string $error Error message
420
     * @return  boolean|string                  True if valid, False if not valid
421
     */
422
    protected function _checkFilters($sqlfilters, &$error = '')
423
    {
424
        // phpcs:enable
425
        $firstandlastparenthesis = 0;
426
        return dolCheckFilters($sqlfilters, $error, $firstandlastparenthesis);
427
    }
428
}
429