ImportCsv::import_insert()   F
last analyzed

Complexity

Conditions 170
Paths > 20000

Size

Total Lines 769
Code Lines 490

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 170
eloc 490
nc 230323205
nop 6
dl 0
loc 769
rs 0
c 0
b 0
f 0

How to fix   Long Method    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) 2006-2012  Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2009-2012	Regis Houssin		        <[email protected]>
5
 * Copyright (C) 2012       Christophe Battarel         <[email protected]>
6
 * Copyright (C) 2012-2016  Juanjo Menent		        <[email protected]>
7
 * Copyright (C) 2024       Frédéric France             <[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
 * or see https://www.gnu.org/
23
 */
24
25
use Dolibarr\Code\Core\Classes\Translate;
26
use Dolibarr\Code\Imports\Classes\ModeleImports;
27
use Dolibarr\Code\Societe\Classes\Societe;
28
use Dolibarr\Lib\Version;
29
30
/**
31
 *      \file       htdocs/core/modules/import/import_csv.modules.php
32
 *      \ingroup    import
33
 *      \brief      File to load import files with CSV format
34
 */
35
36
/**
37
 *  Class to import CSV files
38
 */
39
class ImportCsv extends ModeleImports
40
{
41
    /**
42
     * @var DoliDB Database handler.
43
     */
44
    public $db;
45
46
    /**
47
     * @var string Code of driver
48
     */
49
    public $id;
50
51
    /**
52
     * Dolibarr version of driver
53
     * @var string
54
     */
55
    public $version = 'dolibarr';
56
57
    public $label_lib; // Label of external lib used by driver
58
59
    public $version_lib; // Version of external lib used by driver
60
61
    public $separator;
62
63
    public $file; // Path of file
64
65
    public $handle; // Handle fichier
66
67
    public $cacheconvert = array(); // Array to cache list of value found after a conversion
68
69
    public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
70
71
    public $nbinsert = 0; // # of insert done during the import
72
73
    public $nbupdate = 0; // # of update done during the import
74
75
    public $charset = '';
76
77
    public $col;
78
79
80
    /**
81
     *  Constructor
82
     *
83
     * @param DoliDB $db Database handler
84
     * @param string $datatoimport String code describing import set (ex: 'societe_1')
85
     */
86
    public function __construct($db, $datatoimport)
87
    {
88
        global $langs;
89
90
        parent::__construct();
91
        $this->db = $db;
92
93
        $this->separator = (GETPOST('separator') ? GETPOST('separator') : getDolGlobalString('IMPORT_CSV_SEPARATOR_TO_USE', ','));
94
        $this->enclosure = '"';
95
        $this->escape = '"';
96
97
        $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
98
        $this->label = 'Csv'; // Label of driver
99
        $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
100
        $this->extension = 'csv'; // Extension for generated file by this driver
101
        $this->picto = 'mime/other'; // Picto
102
        $this->version = '1.34'; // Driver version
103
        $this->phpmin = array(7, 0); // Minimum version of PHP required by module
104
105
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/admin.lib.php';
106
        if (Version::compare($this->phpmin, Version::arrayPhp()) > 0) {
107
            dol_syslog("Module need a higher PHP version");
108
            $this->error = "Module need a higher PHP version";
109
            return;
110
        }
111
112
        // If driver use an external library, put its name here
113
        $this->label_lib = 'Dolibarr';
114
        $this->version_lib = DOL_VERSION;
115
116
        $this->datatoimport = $datatoimport;
117
        if (preg_match('/^societe_/', $datatoimport)) {
118
            $this->thirdpartyobject = new Societe($this->db);
119
        }
120
    }
121
122
123
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
124
125
    /**
126
     *  Output header of an example file for this format
127
     *
128
     * @param Translate $outputlangs Output language
129
     * @return string                          Empty string
130
     */
131
    public function write_header_example($outputlangs)
132
    {
133
        // phpcs:enable
134
        return '';
135
    }
136
137
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
138
139
    /**
140
     *  Output title line of an example file for this format
141
     *
142
     * @param Translate $outputlangs Output language
143
     * @param array $headerlinefields Array of fields name
144
     * @return string                          String output
145
     */
146
    public function write_title_example($outputlangs, $headerlinefields)
147
    {
148
        // phpcs:enable
149
        $s = implode($this->separator, array_map('cleansep', $headerlinefields));
150
        return $s . "\n";
151
    }
152
153
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
154
155
    /**
156
     *  Output record of an example file for this format
157
     *
158
     * @param Translate $outputlangs Output language
159
     * @param array $contentlinevalues Array of lines
160
     * @return string                          String output
161
     */
162
    public function write_record_example($outputlangs, $contentlinevalues)
163
    {
164
        // phpcs:enable
165
        $s = implode($this->separator, array_map('cleansep', $contentlinevalues));
166
        return $s . "\n";
167
    }
168
169
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
170
171
    /**
172
     *  Output footer of an example file for this format
173
     *
174
     * @param Translate $outputlangs Output language
175
     * @return string                          Empty string
176
     */
177
    public function write_footer_example($outputlangs)
178
    {
179
        // phpcs:enable
180
        return '';
181
    }
182
183
184
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
185
186
    /**
187
     *  Open input file
188
     *
189
     * @param string $file Path of filename
190
     * @return int                 Return integer <0 if KO, >=0 if OK
191
     */
192
    public function import_open_file($file)
193
    {
194
        // phpcs:enable
195
        global $langs;
196
        $ret = 1;
197
198
        dol_syslog(get_only_class($this) . "::open_file file=" . $file);
199
200
        ini_set('auto_detect_line_endings', 1); // For MAC compatibility
201
202
        $this->handle = fopen(dol_osencode($file), "r");
203
        if (!$this->handle) {
204
            $langs->load("errors");
205
            $this->error = $langs->trans("ErrorFailToOpenFile", $file);
206
            $ret = -1;
207
        } else {
208
            $this->file = $file;
209
        }
210
211
        return $ret;
212
    }
213
214
215
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
216
217
    /**
218
     *  Return nb of records. File must be closed.
219
     *
220
     * @param string $file Path of filename
221
     * @return     int     Return integer <0 if KO, >=0 if OK
222
     */
223
    public function import_get_nb_of_lines($file)
224
    {
225
        // phpcs:enable
226
        return dol_count_nb_of_line($file);
227
    }
228
229
230
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
231
232
    /**
233
     *  Input header line from file
234
     *
235
     * @return     int     Return integer <0 if KO, >=0 if OK
236
     */
237
    public function import_read_header()
238
    {
239
        // phpcs:enable
240
        return 0;
241
    }
242
243
244
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
245
246
    /**
247
     *  Return array of next record in input file.
248
     *
249
     * @return     array|boolean       Array of field values. Data are UTF8 encoded. [fieldpos] => (['val']=>val, ['type']=>-1=null,0=blank,1=not empty string)
250
     */
251
    public function import_read_record()
252
    {
253
        // phpcs:enable
254
        global $conf;
255
256
        $arrayres = fgetcsv($this->handle, 100000, $this->separator, $this->enclosure, $this->escape);
257
258
        // End of file
259
        if ($arrayres === false) {
260
            return false;
261
        }
262
263
        //var_dump($this->handle);
264
        //var_dump($arrayres);exit;
265
        $newarrayres = array();
266
        if ($arrayres && is_array($arrayres)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arrayres of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
267
            foreach ($arrayres as $key => $val) {
268
                if (getDolGlobalString('IMPORT_CSV_FORCE_CHARSET')) {   // Forced charset
269
                    if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8') {
270
                        $newarrayres[$key]['val'] = $val;
271
                        $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
272
                    } else {
273
                        $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
274
                        $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
275
                    }
276
                } else { // Autodetect format (UTF8 or ISO)
277
                    if (utf8_check($val)) {
278
                        $newarrayres[$key]['val'] = $val;
279
                        $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
280
                    } else {
281
                        $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
282
                        $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it's null
283
                    }
284
                }
285
            }
286
287
            $this->col = count($newarrayres);
288
        }
289
290
        return $newarrayres;
291
    }
292
293
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
294
295
    /**
296
     *  Close file handle
297
     *
298
     * @return integer
299
     */
300
    public function import_close_file()
301
    {
302
        // phpcs:enable
303
        fclose($this->handle);
304
        return 0;
305
    }
306
307
308
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
309
310
    /**
311
     * Insert a record into database
312
     *
313
     * @param array $arrayrecord Array of read values: [fieldpos] => (['val']=>val, ['type']=>-1=null,0=blank,1=string), [fieldpos+1]...
314
     * @param array $array_match_file_to_database Array of target fields where to insert data: [fieldpos] => 's.fieldname', [fieldpos+1]...
315
     * @param Object $objimport Object import (contains objimport->array_import_tables, objimport->array_import_fields, objimport->array_import_convertvalue, ...)
316
     * @param int $maxfields Max number of fields to use
317
     * @param string $importid Import key
318
     * @param array $updatekeys Array of keys to use to try to do an update first before insert. This field are defined into the module descriptor.
319
     * @return  int                                     Return integer <0 if KO, >0 if OK
320
     */
321
    public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
322
    {
323
        // phpcs:enable
324
        global $langs, $conf, $user;
325
        global $thirdparty_static; // Specific to thirdparty import
326
        global $tablewithentity_cache; // Cache to avoid to call  desc at each rows on tables
327
328
        $error = 0;
329
        $warning = 0;
330
        $this->errors = array();
331
        $this->warnings = array();
332
333
        //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
334
335
        //var_dump($array_match_file_to_database);
336
        //var_dump($arrayrecord); exit;
337
338
        $array_match_database_to_file = array_flip($array_match_file_to_database);
339
        $sort_array_match_file_to_database = $array_match_file_to_database;
340
        ksort($sort_array_match_file_to_database);
341
342
        //var_dump($sort_array_match_file_to_database);
343
344
        if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
345
            //print 'W';
346
            $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
347
            $this->warnings[$warning]['type'] = 'EMPTY';
348
            $warning++;
349
        } else {
350
            $last_insert_id_array = array(); // store the last inserted auto_increment id for each table, so that dependent tables can be inserted with the appropriate id (eg: extrafields fk_object will be set with the last inserted object's id)
351
            $updatedone = false;
352
            $insertdone = false;
353
            // For each table to insert, me make a separate insert
354
            foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
355
                // Build sql request
356
                $sql = '';
357
                $listfields = array();
358
                $listvalues = array();
359
                $i = 0;
360
                $errorforthistable = 0;
361
362
                // Define $tablewithentity_cache[$tablename] if not already defined
363
                if (!isset($tablewithentity_cache[$tablename])) {   // keep this test with "isset"
364
                    dol_syslog("Check if table " . $tablename . " has an entity field");
365
                    $resql = $this->db->DDLDescTable($tablename, 'entity');
366
                    if ($resql) {
367
                        $obj = $this->db->fetch_object($resql);
368
                        if ($obj) {
369
                            $tablewithentity_cache[$tablename] = 1; // table contains entity field
370
                        } else {
371
                            $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
372
                        }
373
                    } else {
374
                        dol_print_error($this->db);
375
                    }
376
                } else {
377
                    //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
378
                }
379
380
                // Define array to convert fields ('c.ref', ...) into column index (1, ...)
381
                $arrayfield = array();
382
                foreach ($sort_array_match_file_to_database as $key => $val) {
383
                    $arrayfield[$val] = ($key - 1);
384
                }
385
386
                // $arrayrecord start at key 0
387
                // $sort_array_match_file_to_database start at key 1
388
389
                // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
390
                foreach ($sort_array_match_file_to_database as $key => $val) {
391
                    $fieldalias = preg_replace('/\..*$/i', '', $val);
392
                    $fieldname = preg_replace('/^.*\./i', '', $val);
393
394
                    if ($alias != $fieldalias) {
395
                        continue; // Not a field of current table
396
                    }
397
398
                    if ($key <= $maxfields) {
399
                        // Set $newval with value to insert and set $listvalues with sql request part for insert
400
                        $newval = '';
401
                        if ($arrayrecord[($key - 1)]['type'] > 0) {
402
                            $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
403
                        }
404
405
                        //var_dump($newval);var_dump($val);
406
                        //var_dump($objimport->array_import_convertvalue[0][$val]);
407
408
                        // Make some tests on $newval
409
410
                        // Is it a required field ?
411
                        if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string)$newval == '')) {
412
                            // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
413
                            $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
414
                            $this->errors[$error]['type'] = 'NOTNULL';
415
                            $errorforthistable++;
416
                            $error++;
417
                        } else {
418
                            // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
419
                            // We convert field if required
420
                            if (!empty($objimport->array_import_convertvalue[0][$val])) {
421
                                //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
422
                                if (
423
                                    $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
424
                                    || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
425
                                    || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
426
                                ) {
427
                                    // New val can be an id or ref. If it start with id: it is forced to id, if it start with ref: it is forced to ref. It not, we try to guess.
428
                                    $isidorref = 'id';
429
                                    if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
430
                                        $isidorref = 'ref';
431
                                    }
432
433
                                    $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
434
                                    //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
435
436
                                    if ($isidorref == 'ref') {    // If value into input import file is a ref, we apply the function defined into descriptor
437
                                        $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
438
                                        $class = $objimport->array_import_convertvalue[0][$val]['class'];
439
                                        $method = $objimport->array_import_convertvalue[0][$val]['method'];
440
                                        if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] != '') {
441
                                            $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval];
442
                                        } else {
443
                                            $resultload = dol_include_once($file);
444
                                            if (empty($resultload)) {
445
                                                dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
446
                                                break;
447
                                            }
448
                                            $classinstance = new $class($this->db);
449
                                            if ($class == 'CGenericDic') {
450
                                                $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
451
                                                $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
452
                                            }
453
454
                                            // Try the fetch from code or ref
455
                                            $param_array = array('', $newval);
456
                                            if ($class == 'AccountingAccount') {
457
                                                //var_dump($arrayrecord[0]['val']);
458
                                                /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
459
                                                 $tmpchartofaccount = new AccountancySystem($this->db);
460
                                                 $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
461
                                                 //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
462
                                                 if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
463
                                                 {
464
                                                 $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
465
                                                 $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
466
                                                 $errorforthistable++;
467
                                                 $error++;
468
                                                 }*/
469
                                                $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
470
                                            }
471
                                            if ($class == 'CActionComm') {
472
                                                $param_array = array($newval); // CActionComm fetch method have same parameter for id and code
473
                                            }
474
                                            $result = call_user_func_array(array($classinstance, $method), $param_array);
475
476
                                            // If duplicate record found
477
                                            if (!($classinstance->id != '') && $result == -2) {
478
                                                $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
479
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
480
                                                $errorforthistable++;
481
                                                $error++;
482
                                            }
483
484
                                            // If not found, try the fetch from label
485
                                            if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
486
                                                $param_array = array('', '', $newval);
487
                                                call_user_func_array(array($classinstance, $method), $param_array);
488
                                            }
489
                                            $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] = $classinstance->id;
490
491
                                            //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
492
                                            if ($classinstance->id != '') { // id may be 0, it is a found value
493
                                                $newval = $classinstance->id;
494
                                            } elseif (!$error) {
495
                                                if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
496
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
497
                                                } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
498
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
499
                                                } else {
500
                                                    $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
501
                                                }
502
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
503
                                                $errorforthistable++;
504
                                                $error++;
505
                                            }
506
                                        }
507
                                    }
508
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
509
                                    $isidorref = 'id';
510
                                    if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
511
                                        $isidorref = 'ref';
512
                                    }
513
                                    $newval = preg_replace('/^(id|ref):/i', '', $newval);
514
515
                                    if ($isidorref == 'ref') {
516
                                        $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
517
                                        $class = $objimport->array_import_convertvalue[0][$val]['class'];
518
                                        $method = $objimport->array_import_convertvalue[0][$val]['method'];
519
                                        $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
520
                                        $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
521
                                        if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] != '') {
522
                                            $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval];
523
                                        } else {
524
                                            $resultload = dol_include_once($file);
525
                                            if (empty($resultload)) {
526
                                                dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', code=' . $code);
527
                                                break;
528
                                            }
529
                                            $classinstance = new $class($this->db);
530
                                            // Try the fetch from code and ref
531
                                            $param_array = array('', $newval, $code);
532
                                            call_user_func_array(array($classinstance, $method), $param_array);
533
                                            $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] = $classinstance->id;
534
                                            if ($classinstance->id > 0) {    // we found record
535
                                                $newval = $classinstance->id;
536
                                            } else {
537
                                                if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
538
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
539
                                                } else {
540
                                                    $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
541
                                                }
542
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
543
                                                $errorforthistable++;
544
                                                $error++;
545
                                            }
546
                                        }
547
                                    }
548
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
549
                                    if (empty($newval)) {
550
                                        $newval = '0';
551
                                    }
552
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
553
                                    $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
554
                                    $class = $objimport->array_import_convertvalue[0][$val]['class'];
555
                                    $method = $objimport->array_import_convertvalue[0][$val]['method'];
556
                                    $units = $objimport->array_import_convertvalue[0][$val]['units'];
557
                                    if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] != '') {
558
                                        $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval];
559
                                    } else {
560
                                        $resultload = dol_include_once($file);
561
                                        if (empty($resultload)) {
562
                                            dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', units=' . $units);
563
                                            break;
564
                                        }
565
                                        $classinstance = new $class($this->db);
566
                                        // Try the fetch from code or ref
567
                                        call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
568
                                        $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
569
                                        $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] = $scaleorid;
570
                                        //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
571
                                        if ($classinstance->id > 0) {   // we found record
572
                                            $newval = $scaleorid ? $scaleorid : 0;
573
                                        } else {
574
                                            if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
575
                                                $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
576
                                            } else {
577
                                                $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
578
                                            }
579
                                            $this->errors[$error]['type'] = 'FOREIGNKEY';
580
                                            $errorforthistable++;
581
                                            $error++;
582
                                        }
583
                                    }
584
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
585
                                    if (strtolower($newval) == 'auto') {
586
                                        $this->thirdpartyobject->get_codeclient(0, 0);
587
                                        $newval = $this->thirdpartyobject->code_client;
588
                                        //print 'code_client='.$newval;
589
                                    }
590
                                    if (empty($newval)) {
591
                                        $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
592
                                    }
593
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
594
                                    if (strtolower($newval) == 'auto') {
595
                                        $this->thirdpartyobject->get_codefournisseur(0, 1);
596
                                        $newval = $this->thirdpartyobject->code_fournisseur;
597
                                        //print 'code_fournisseur='.$newval;
598
                                    }
599
                                    if (empty($newval)) {
600
                                        $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
601
                                    }
602
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
603
                                    if (strtolower($newval) == 'auto') {
604
                                        $this->thirdpartyobject->get_codecompta('customer');
605
                                        $newval = $this->thirdpartyobject->code_compta;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Societe\Cl...s\Societe::$code_compta has been deprecated: Use $code_compta_client ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

605
                                        $newval = /** @scrutinizer ignore-deprecated */ $this->thirdpartyobject->code_compta;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
606
                                        //print 'code_compta='.$newval;
607
                                    }
608
                                    if (empty($newval)) {
609
                                        $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
610
                                    }
611
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
612
                                    if (strtolower($newval) == 'auto') {
613
                                        $this->thirdpartyobject->get_codecompta('supplier');
614
                                        $newval = $this->thirdpartyobject->code_compta_fournisseur;
615
                                        if (empty($newval)) {
616
                                            $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
617
                                        }
618
                                        //print 'code_compta_fournisseur='.$newval;
619
                                    }
620
                                    if (empty($newval)) {
621
                                        $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
622
                                    }
623
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
624
                                    if (strtolower($newval) == 'auto') {
625
                                        $defaultref = '';
626
627
                                        $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
628
                                        $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
629
630
                                        if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT . $pathModForNumber)) {
631
                                            require_once DOL_DOCUMENT_ROOT . $pathModForNumber;
632
                                            $modForNumber = new $classModForNumber();
633
634
                                            $tmpobject = null;
635
                                            // Set the object with the date property when we can
636
                                            if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
637
                                                $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
638
                                                require_once DOL_DOCUMENT_ROOT . $pathForObject;
639
                                                $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
640
                                                $tmpobject = new $tmpclassobject($this->db);
641
                                                foreach ($arrayfield as $tmpkey => $tmpval) {   // $arrayfield is array('c.ref'=>0, ...)
642
                                                    if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
643
                                                        $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
644
                                                    }
645
                                                }
646
                                            }
647
648
                                            $defaultref = $modForNumber->getNextValue(null, $tmpobject);
649
                                        }
650
                                        if (is_numeric($defaultref) && $defaultref <= 0) {  // If error
651
                                            $defaultref = '';
652
                                        }
653
                                        $newval = $defaultref;
654
                                    }
655
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
656
                                    $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
657
                                    $class = $objimport->array_import_convertvalue[0][$val]['class'];
658
                                    $method = $objimport->array_import_convertvalue[0][$val]['method'];
659
                                    $resultload = dol_include_once($file);
660
                                    if (empty($resultload)) {
661
                                        dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
662
                                        break;
663
                                    }
664
                                    $classinstance = new $class($this->db);
665
                                    $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
666
                                    if (empty($classinstance->error) && empty($classinstance->errors)) {
667
                                        $newval = $res;     // We get new value computed.
668
                                    } else {
669
                                        $this->errors[$error]['type'] = 'CLASSERROR';
670
                                        $this->errors[$error]['lib'] = implode(
671
                                            "\n",
672
                                            array_merge([$classinstance->error], $classinstance->errors)
673
                                        );
674
                                        $errorforthistable++;
675
                                        $error++;
676
                                    }
677
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
678
                                    $newval = price2num($newval);
679
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
680
                                    if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
681
                                        $newval = rtrim(trim($newval), "0");
682
                                    } else {
683
                                        $newval = trim($newval);
684
                                    }
685
                                }
686
687
                                //print 'Val to use as insert is '.$newval.'<br>';
688
                            }
689
690
                            // Test regexp
691
                            if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
692
                                // If test regex string is "field@table" or "field@table:..." (means must exists into table ...)
693
                                $reg = array();
694
                                if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
695
                                    $field = $reg[1];
696
                                    $table = $reg[2];
697
                                    $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
698
699
                                    $cachekey = $field . '@' . $table;
700
                                    if (!empty($filter)) {
701
                                        $cachekey .= ':' . $filter;
702
                                    }
703
704
                                    // Load content of field@table into cache array
705
                                    if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
706
                                        $sql = "SELECT " . $field . " as aliasfield FROM " . $table;
707
                                        if (!empty($filter)) {
708
                                            $sql .= ' WHERE ' . $filter;
709
                                        }
710
711
                                        $resql = $this->db->query($sql);
712
                                        if ($resql) {
713
                                            $num = $this->db->num_rows($resql);
714
                                            $i = 0;
715
                                            while ($i < $num) {
716
                                                $obj = $this->db->fetch_object($resql);
717
                                                if ($obj) {
718
                                                    $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
719
                                                }
720
                                                $i++;
721
                                            }
722
                                        } else {
723
                                            dol_print_error($this->db);
724
                                        }
725
                                    }
726
727
                                    // Now we check cache is not empty (should not) and key is into cache
728
                                    if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
729
                                        $tableforerror = $table;
730
                                        if (!empty($filter)) {
731
                                            $tableforerror .= ':' . $filter;
732
                                        }
733
                                        $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
734
                                        $this->errors[$error]['type'] = 'FOREIGNKEY';
735
                                        $errorforthistable++;
736
                                        $error++;
737
                                    }
738
                                } elseif (!preg_match('/' . $objimport->array_import_regex[0][$val] . '/i', $newval)) {
739
                                    // If test is just a static regex
740
                                    //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
741
                                    $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
742
                                    $this->errors[$error]['type'] = 'REGEX';
743
                                    $errorforthistable++;
744
                                    $error++;
745
                                }
746
                            }
747
748
                            // Check HTML injection
749
                            $inj = Filters::testSqlAndScriptInject($newval, 0);
750
                            if ($inj) {
751
                                $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
752
                                $this->errors[$error]['type'] = 'HTMLINJECTION';
753
                                $errorforthistable++;
754
                                $error++;
755
                            }
756
757
                            // Other tests
758
                            // ...
759
                        }
760
761
                        // Define $listfields and $listvalues to build the SQL request
762
                        if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
763
                            if (!in_array("socialnetworks", $listfields)) {
764
                                $listfields[] = "socialnetworks";
765
                                $socialkey = array_search("socialnetworks", $listfields);   // Return position of 'socialnetworks' key in array
766
                                $listvalues[$socialkey] = '';
767
                            }
768
                            //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
769
                            if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
770
                                $socialkey = array_search("socialnetworks", $listfields);   // Return position of 'socialnetworks' key in array
771
                                //var_dump('sk='.$socialkey);   // socialkey=19
772
                                $socialnetwork = explode("_", $fieldname)[1];
773
                                if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
774
                                    $json = new stdClass();
775
                                    $json->$socialnetwork = $newval;
776
                                    $listvalues[$socialkey] = json_encode($json);
777
                                } else {
778
                                    $jsondata = $listvalues[$socialkey];
779
                                    $json = json_decode($jsondata);
780
                                    $json->$socialnetwork = $newval;
781
                                    $listvalues[$socialkey] = json_encode($json);
782
                                }
783
                            }
784
                        } else {
785
                            $listfields[] = $fieldname;
786
                            // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
787
                            if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
788
                                $listvalues[] = ($newval == '0' ? (int)$newval : "null");
789
                            } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
790
                                $listvalues[] = "''";
791
                            } else {
792
                                $listvalues[] = "'" . $this->db->escape($newval) . "'";
793
                            }
794
                        }
795
                    }
796
                    $i++;
797
                }
798
799
                // We add hidden fields (but only if there is at least one field to add into table)
800
                // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
801
                // Previously we processed the ->import_fields_array.
802
                if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
803
                    // Loop on each hidden fields to add them into listfields/listvalues
804
                    foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
805
                        if (!preg_match('/^' . preg_quote($alias, '/') . '\./', $tmpkey)) {
806
                            continue; // Not a field of current table
807
                        }
808
                        $keyfield = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $tmpkey);
809
810
                        if (in_array($keyfield, $listfields)) {     // avoid duplicates in insert
811
                            continue;
812
                        } elseif ($tmpval == 'user->id') {
813
                            $listfields[] = $keyfield;
814
                            $listvalues[] = ((int)$user->id);
815
                        } elseif (preg_match('/^lastrowid-/', $tmpval)) {
816
                            $tmp = explode('-', $tmpval);
817
                            $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
818
                            $listfields[] = $keyfield;
819
                            $listvalues[] = (int)$lastinsertid;
820
                            //print $tmpkey."-".$tmpval."-".$listfields."-".$listvalues."<br>";exit;
821
                        } elseif (preg_match('/^const-/', $tmpval)) {
822
                            $tmp = explode('-', $tmpval, 2);
823
                            $listfields[] = $keyfield;
824
                            $listvalues[] = "'" . $this->db->escape($tmp[1]) . "'";
825
                        } elseif (preg_match('/^rule-/', $tmpval)) {
826
                            $fieldname = $tmpkey;
827
                            if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
828
                                if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
829
                                    $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
830
                                    $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
831
                                    $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
832
                                    $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
833
                                    $resultload = dol_include_once($file);
834
                                    if (empty($resultload)) {
835
                                        dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
836
                                        break;
837
                                    }
838
                                    $classinstance = new $class($this->db);
839
                                    $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
840
                                    if (empty($classinstance->error) && empty($classinstance->errors)) {
841
                                        $fieldArr = explode('.', $fieldname);
842
                                        if (count($fieldArr) > 0) {
843
                                            $fieldname = $fieldArr[1];
844
                                        }
845
846
                                        // Set $listfields and $listvalues
847
                                        $listfields[] = $fieldname;
848
                                        if ($type == 'int') {
849
                                            $listvalues[] = (int)$res;
850
                                        } elseif ($type == 'double') {
851
                                            $listvalues[] = (float)$res;
852
                                        } else {
853
                                            $listvalues[] = "'" . $this->db->escape($res) . "'";
854
                                        }
855
                                    } else {
856
                                        $this->errors[$error]['type'] = 'CLASSERROR';
857
                                        $this->errors[$error]['lib'] = implode(
858
                                            "\n",
859
                                            array_merge([$classinstance->error], $classinstance->errors)
860
                                        );
861
                                        $errorforthistable++;
862
                                        $error++;
863
                                    }
864
                                }
865
                            }
866
                        } else {
867
                            $this->errors[$error]['lib'] = 'Bad value of profile setup ' . $tmpval . ' for array_import_fieldshidden';
868
                            $this->errors[$error]['type'] = 'Import profile setup';
869
                            $error++;
870
                        }
871
                    }
872
                }
873
                //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
874
875
                // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
876
                // so we can try to make the insert or update now.
877
                if (!$errorforthistable) {
878
                    //print "$alias/$tablename/$listfields/$listvalues<br>";
879
                    if (!empty($listfields)) {
880
                        $updatedone = false;
881
                        $insertdone = false;
882
883
                        $is_table_category_link = false;
884
                        $fname = 'rowid';
885
                        if (strpos($tablename, '_categorie_') !== false) {
886
                            $is_table_category_link = true;
887
                            $fname = '*';
888
                        }
889
890
                        if (!empty($updatekeys)) {
891
                            // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
892
893
                            if (empty($lastinsertid)) { // No insert done yet for a parent table
894
                                $sqlSelect = "SELECT " . $fname . " FROM " . $tablename;
895
                                $data = array_combine($listfields, $listvalues);
896
                                $where = array();   // filters to forge SQL request
897
                                $filters = array(); // filters to forge output error message
898
                                foreach ($updatekeys as $key) {
899
                                    $col = $objimport->array_import_updatekeys[0][$key];
900
                                    $key = preg_replace('/^.*\./i', '', $key);
901
                                    if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
902
                                        $tmp = explode("_", $key);
903
                                        $key = $tmp[0];
904
                                        $socialnetwork = $tmp[1];
905
                                        $jsondata = $data[$key];
906
                                        $json = json_decode($jsondata);
907
                                        $stringtosearch = json_encode($socialnetwork) . ':' . json_encode($json->$socialnetwork);
908
                                        //var_dump($stringtosearch);
909
                                        //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
910
                                        $where[] = $key . " LIKE '%" . $this->db->escape($this->db->escapeforlike($stringtosearch)) . "%'";
911
                                        $filters[] = $col . " LIKE '%" . $this->db->escape($this->db->escapeforlike($stringtosearch)) . "%'";
912
                                        //var_dump($where[1]); // This provide a value for sql string inside a like
913
                                    } else {
914
                                        $where[] = $key . ' = ' . $data[$key];
915
                                        $filters[] = $col . ' = ' . $data[$key];
916
                                    }
917
                                }
918
                                if (!empty($tablewithentity_cache[$tablename])) {
919
                                    $where[] = "entity IN (" . getEntity($this->getElementFromTableWithPrefix($tablename)) . ")";
920
                                    $filters[] = "entity IN (" . getEntity($this->getElementFromTableWithPrefix($tablename)) . ")";
921
                                }
922
                                $sqlSelect .= " WHERE " . implode(' AND ', $where);
923
924
                                $resql = $this->db->query($sqlSelect);
925
                                if ($resql) {
926
                                    $num_rows = $this->db->num_rows($resql);
927
                                    if ($num_rows == 1) {
928
                                        $res = $this->db->fetch_object($resql);
929
                                        $lastinsertid = $res->rowid;
930
                                        if ($is_table_category_link) {
931
                                            $lastinsertid = 'linktable';
932
                                        } // used to apply update on tables like llx_categorie_product and avoid being blocked for all file content if at least one entry already exists
933
                                        $last_insert_id_array[$tablename] = $lastinsertid;
934
                                    } elseif ($num_rows > 1) {
935
                                        $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
936
                                        $this->errors[$error]['type'] = 'SQL';
937
                                        $error++;
938
                                    } else {
939
                                        // No record found with filters, insert will be tried below
940
                                    }
941
                                } else {
942
                                    //print 'E';
943
                                    $this->errors[$error]['lib'] = $this->db->lasterror();
944
                                    $this->errors[$error]['type'] = 'SQL';
945
                                    $error++;
946
                                }
947
                            } else {
948
                                // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
949
                                // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
950
                                // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
951
                                // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
952
                                // Note: For extrafield tablename, we have in importfieldshidden_array an entry 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
953
                                $sqlSelect = "SELECT rowid FROM " . $tablename;
954
955
                                if (empty($keyfield)) {
956
                                    $keyfield = 'rowid';
957
                                }
958
                                $sqlSelect .= " WHERE " . $keyfield . " = " . ((int)$lastinsertid);
959
960
                                if (!empty($tablewithentity_cache[$tablename])) {
961
                                    $sqlSelect .= " AND entity IN (" . getEntity($this->getElementFromTableWithPrefix($tablename)) . ")";
962
                                }
963
964
                                $resql = $this->db->query($sqlSelect);
965
                                if ($resql) {
966
                                    $res = $this->db->fetch_object($resql);
967
                                    if ($this->db->num_rows($resql) == 1) {
968
                                        // We have a row referencing this last foreign key, continue with UPDATE.
969
                                    } else {
970
                                        // No record found referencing this last foreign key,
971
                                        // force $lastinsertid to 0 so we INSERT below.
972
                                        $lastinsertid = 0;
973
                                    }
974
                                } else {
975
                                    //print 'E';
976
                                    $this->errors[$error]['lib'] = $this->db->lasterror();
977
                                    $this->errors[$error]['type'] = 'SQL';
978
                                    $error++;
979
                                }
980
                            }
981
982
                            if (!empty($lastinsertid)) {
983
                                // We db escape social network field because he isn't in field creation
984
                                if (in_array("socialnetworks", $listfields)) {
985
                                    $socialkey = array_search("socialnetworks", $listfields);
986
                                    $tmpsql = $listvalues[$socialkey];
987
                                    $listvalues[$socialkey] = "'" . $this->db->escape($tmpsql) . "'";
988
                                }
989
990
                                // Build SQL UPDATE request
991
                                $sqlstart = "UPDATE " . $tablename;
992
993
                                $data = array_combine($listfields, $listvalues);
994
                                $set = array();
995
                                foreach ($data as $key => $val) {
996
                                    $set[] = $key . " = " . $val;   // $val was escaped/sanitized previously
997
                                }
998
                                $sqlstart .= " SET " . implode(', ', $set) . ", import_key = '" . $this->db->escape($importid) . "'";
999
1000
                                if (empty($keyfield)) {
1001
                                    $keyfield = 'rowid';
1002
                                }
1003
                                $sqlend = " WHERE " . $keyfield . " = " . ((int)$lastinsertid);
1004
1005
                                if ($is_table_category_link) {
1006
                                    '@phan-var-force string[] $where';
1007
                                    $sqlend = " WHERE " . implode(' AND ', $where);
1008
                                }
1009
1010
                                if (!empty($tablewithentity_cache[$tablename])) {
1011
                                    $sqlend .= " AND entity IN (" . getEntity($this->getElementFromTableWithPrefix($tablename)) . ")";
1012
                                }
1013
1014
                                $sql = $sqlstart . $sqlend;
1015
1016
                                // Run update request
1017
                                $resql = $this->db->query($sql);
1018
                                if ($resql) {
1019
                                    // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
1020
                                    $updatedone = true;
1021
                                } else {
1022
                                    //print 'E';
1023
                                    $this->errors[$error]['lib'] = $this->db->lasterror();
1024
                                    $this->errors[$error]['type'] = 'SQL';
1025
                                    $error++;
1026
                                }
1027
                            }
1028
                        }
1029
1030
                        // Update not done, we do insert
1031
                        if (!$error && !$updatedone) {
1032
                            // We db escape social network field because he isn't in field creation
1033
                            if (in_array("socialnetworks", $listfields)) {
1034
                                $socialkey = array_search("socialnetworks", $listfields);
1035
                                $tmpsql = $listvalues[$socialkey];
1036
                                $listvalues[$socialkey] = "'" . $this->db->escape($tmpsql) . "'";
1037
                            }
1038
1039
                            // Build SQL INSERT request
1040
                            $sqlstart = "INSERT INTO " . $tablename . "(" . implode(", ", $listfields) . ", import_key";
1041
                            $sqlend = ") VALUES(" . implode(', ', $listvalues) . ", '" . $this->db->escape($importid) . "'";
1042
                            if (!empty($tablewithentity_cache[$tablename])) {
1043
                                $sqlstart .= ", entity";
1044
                                $sqlend .= ", " . $conf->entity;
1045
                            }
1046
                            if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1047
                                $sqlstart .= ", " . $objimport->array_import_tables_creator[0][$alias];
1048
                                $sqlend .= ", " . $user->id;
1049
                            }
1050
                            $sql = $sqlstart . $sqlend . ")";
1051
                            //dol_syslog("import_csv.modules", LOG_DEBUG);
1052
1053
                            // Run insert request
1054
                            if ($sql) {
1055
                                $resql = $this->db->query($sql);
1056
                                if ($resql) {
1057
                                    if (!$is_table_category_link) {
1058
                                        $last_insert_id_array[$tablename] = $this->db->last_insert_id($tablename); // store the last inserted auto_increment id for each table, so that child tables can be inserted with the appropriate id. This must be done just after the INSERT request, else we risk losing the id (because another sql query will be issued somewhere in Dolibarr).
1059
                                    }
1060
                                    $insertdone = true;
1061
                                } else {
1062
                                    //print 'E';
1063
                                    $this->errors[$error]['lib'] = $this->db->lasterror();
1064
                                    $this->errors[$error]['type'] = 'SQL';
1065
                                    $error++;
1066
                                }
1067
                            }
1068
                        }
1069
                    }
1070
                    /*else
1071
                    {
1072
                        dol_print_error(null,'ErrorFieldListEmptyFor '.$alias."/".$tablename);
1073
                    }*/
1074
                }
1075
1076
                if ($error) {
1077
                    break;
1078
                }
1079
            }
1080
1081
            if ($updatedone) {
1082
                $this->nbupdate++;
1083
            }
1084
            if ($insertdone) {
1085
                $this->nbinsert++;
1086
            }
1087
        }
1088
1089
        return 1;
1090
    }
1091
}
1092
1093
/**
1094
 *  Clean a string from separator
1095
 *
1096
 * @param string $value Remove standard separators
1097
 * @return string          String without separators
1098
 */
1099
function cleansep($value)
1100
{
1101
    return str_replace(array(',', ';'), '/', $value);
1102
}
1103