ImportXlsx::import_insert()   F
last analyzed

Complexity

Conditions 167
Paths > 20000

Size

Total Lines 774
Code Lines 488

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 167
eloc 488
nc 191936005
nop 6
dl 0
loc 774
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		MDW							<[email protected]>
8
 * Copyright (C) 2024       Frédéric France             <[email protected]>
9
 * Copyright (C) 2024       Rafael San José             <[email protected]>
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23
 * or see https://www.gnu.org/
24
 */
25
26
use Dolibarr\Code\Core\Classes\Translate;
27
use Dolibarr\Code\Imports\Classes\ModeleImports;
28
use Dolibarr\Code\Societe\Classes\Societe;
29
use Dolibarr\Lib\Version;
30
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
31
use PhpOffice\PhpSpreadsheet\Spreadsheet;
32
use PhpOffice\PhpSpreadsheet\Style\Alignment;
33
34
/**
35
 *      \file       htdocs/core/modules/import/import_xlsx.modules.php
36
 *      \ingroup    import
37
 *      \brief      File to load import files with Excel format
38
 */
39
40
/**
41
 *  Class to import Excel files
42
 */
43
class ImportXlsx extends ModeleImports
44
{
45
    /**
46
     * @var DoliDB Database handler.
47
     */
48
    public $db;
49
50
    /**
51
     * @var string Code of driver
52
     */
53
    public $id;
54
55
    /**
56
     * Dolibarr version of driver
57
     * @var string
58
     */
59
    public $version = 'dolibarr';
60
61
    public $label_lib; // Label of external lib used by driver
62
63
    public $version_lib; // Version of external lib used by driver
64
65
    public $separator;
66
67
    public $file; // Path of file
68
69
    public $handle; // Handle fichier
70
71
    public $cacheconvert = array(); // Array to cache list of value found after a conversion
72
73
    public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
74
75
    public $nbinsert = 0; // # of insert done during the import
76
77
    public $nbupdate = 0; // # of update done during the import
78
79
    public $workbook; // temporary import file
80
81
    public $record; // current record
82
83
    public $headers;
84
85
86
    /**
87
     *  Constructor
88
     *
89
     * @param DoliDB $db Database handler
90
     * @param string $datatoimport String code describing import set (ex: 'societe_1')
91
     */
92
    public function __construct($db, $datatoimport)
93
    {
94
        global $langs;
95
96
        parent::__construct();
97
        $this->db = $db;
98
99
        // this is used as an extension from the example file code, so we have to put xlsx here !!!
100
        $this->id = 'xlsx'; // Same value as xxx in file name export_xxx.modules.php
101
        $this->label = 'Excel 2007'; // Label of driver
102
        $this->desc = $langs->trans("Excel2007FormatDesc");
103
        $this->extension = 'xlsx'; // Extension for generated file by this driver
104
        $this->picto = 'mime/xls'; // Picto (This is not used by the example file code as Mime type, too bad ...)
105
        $this->version = '1.0'; // Driver version
106
        $this->phpmin = array(7, 1); // Minimum version of PHP required by module
107
108
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/admin.lib.php';
109
        if (Version::compare($this->phpmin, Version::arrayPhp()) > 0) {
110
            dol_syslog("Module need a higher PHP version");
111
            $this->error = "Module need a higher PHP version";
112
            return;
113
        }
114
115
        // If driver use an external library, put its name here
116
        require_once constant('DOL_DOCUMENT_ROOT') . '/includes/phpoffice/phpspreadsheet/src/autoloader.php';
117
        require_once constant('DOL_DOCUMENT_ROOT') . '/includes/Psr/autoloader.php';
118
        require_once PHPEXCELNEW_PATH . 'Spreadsheet.php';
119
        $this->workbook = new Spreadsheet();
120
121
        // If driver use an external library, put its name here
122
        if (!class_exists('ZipArchive')) {  // For Excel2007
123
            $langs->load("errors");
124
            $this->error = $langs->trans('ErrorPHPNeedModule', 'zip');
125
            return;
126
        }
127
        $this->label_lib = 'PhpSpreadSheet';
128
        $this->version_lib = '1.8.0';
129
130
        $this->datatoimport = $datatoimport;
131
        if (preg_match('/^societe_/', $datatoimport)) {
132
            $this->thirdpartyobject = new Societe($this->db);
133
        }
134
    }
135
136
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
137
138
    /**
139
     *  Output header of an example file for this format
140
     *
141
     * @param Translate $outputlangs Output language
142
     * @return string                          Empty string
143
     */
144
    public function write_header_example($outputlangs)
145
    {
146
        // phpcs:enable
147
        global $user, $conf, $langs, $file;
148
        // create a temporary object, the final output will be generated in footer
149
        $this->workbook->getProperties()->setCreator($user->getFullName($outputlangs) . ' - Dolibarr ' . DOL_VERSION);
150
        $this->workbook->getProperties()->setTitle($outputlangs->trans("Import") . ' - ' . $file);
151
        $this->workbook->getProperties()->setSubject($outputlangs->trans("Import") . ' - ' . $file);
152
        $this->workbook->getProperties()->setDescription($outputlangs->trans("Import") . ' - ' . $file);
153
154
        $this->workbook->setActiveSheetIndex(0);
155
        $this->workbook->getActiveSheet()->setTitle($outputlangs->trans("Sheet"));
156
        $this->workbook->getActiveSheet()->getDefaultRowDimension()->setRowHeight(16);
157
158
        return '';
159
    }
160
161
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
162
163
    /**
164
     *  Output title line of an example file for this format
165
     *
166
     * @param Translate $outputlangs Output language
167
     * @param array $headerlinefields Array of fields name
168
     * @return string                          String output
169
     */
170
    public function write_title_example($outputlangs, $headerlinefields)
171
    {
172
        // phpcs:enable
173
        global $conf;
174
        $this->workbook->getActiveSheet()->getStyle('1')->getFont()->setBold(true);
175
        $this->workbook->getActiveSheet()->getStyle('1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
176
177
        $col = 1;
178
        foreach ($headerlinefields as $field) {
179
            $this->workbook->getActiveSheet()->SetCellValueByColumnAndRow($col, 1, $outputlangs->transnoentities($field));
180
            // set autowidth
181
            //$this->workbook->getActiveSheet()->getColumnDimension($this->column2Letter($col + 1))->setAutoSize(true);
182
            $col++;
183
        }
184
185
        return ''; // final output will be generated in footer
186
    }
187
188
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
189
190
    /**
191
     *  Output record of an example file for this format
192
     *
193
     * @param Translate $outputlangs Output language
194
     * @param array $contentlinevalues Array of lines
195
     * @return string                          Empty string
196
     */
197
    public function write_record_example($outputlangs, $contentlinevalues)
198
    {
199
        // phpcs:enable
200
        $col = 1;
201
        $row = 2;
202
        foreach ($contentlinevalues as $cell) {
203
            $this->workbook->getActiveSheet()->SetCellValueByColumnAndRow($col, $row, $cell);
204
            $col++;
205
        }
206
207
        return ''; // final output will be generated in footer
208
    }
209
210
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
211
212
    /**
213
     *  Output footer of an example file for this format
214
     *
215
     * @param Translate $outputlangs Output language
216
     * @return string                          String output
217
     */
218
    public function write_footer_example($outputlangs)
219
    {
220
        // phpcs:enable
221
        // return the file content as a string
222
        $tempfile = tempnam(sys_get_temp_dir(), 'dol');
223
        $objWriter = new PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->workbook);
224
        $objWriter->save($tempfile);
225
        $this->workbook->disconnectWorksheets();
226
        unset($this->workbook);
227
228
        $content = file_get_contents($tempfile);
229
        unlink($tempfile);
230
        return $content;
231
    }
232
233
234
235
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
236
237
    /**
238
     *  Open input file
239
     *
240
     * @param string $file Path of filename
241
     * @return int                 Return integer <0 if KO, >=0 if OK
242
     */
243
    public function import_open_file($file)
244
    {
245
        // phpcs:enable
246
        global $langs;
247
        $ret = 1;
248
249
        dol_syslog(get_only_class($this) . "::open_file file=" . $file);
250
251
        $reader = new Xlsx();
252
        $this->workbook = $reader->load($file);
253
        $this->record = 1;
254
        $this->file = $file;
255
256
        return $ret;
257
    }
258
259
260
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
261
262
    /**
263
     *  Return nb of records. File must be closed.
264
     *
265
     * @param string $file Path of filename
266
     * @return int                 Return integer <0 if KO, >=0 if OK
267
     */
268
    public function import_get_nb_of_lines($file)
269
    {
270
        // phpcs:enable
271
        $reader = new Xlsx();
272
        $this->workbook = $reader->load($file);
273
274
        $rowcount = $this->workbook->getActiveSheet()->getHighestDataRow();
275
276
        $this->workbook->disconnectWorksheets();
277
        unset($this->workbook);
278
279
        return $rowcount;
280
    }
281
282
283
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
284
285
    /**
286
     *  Input header line from file
287
     *
288
     * @return     int     Return integer <0 if KO, >=0 if OK
289
     */
290
    public function import_read_header()
291
    {
292
        // phpcs:enable
293
        // This is not called by the import code !!!
294
        $this->headers = array();
295
        $xlsx = new Xlsx();
296
        $info = $xlsx->listWorksheetinfo($this->file);
297
        $countcolumns = $info[0]['totalColumns'];
298
        for ($col = 1; $col <= $countcolumns; $col++) {
299
            $this->headers[$col] = $this->workbook->getActiveSheet()->getCellByColumnAndRow($col, 1)->getValue();
300
        }
301
        return 0;
302
    }
303
304
305
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
306
307
    /**
308
     *  Return array of next record in input file.
309
     *
310
     * @return     array|boolean       Array of field values. Data are UTF8 encoded. [fieldpos] => (['val']=>val, ['type']=>-1=null,0=blank,1=not empty string)
311
     */
312
    public function import_read_record()
313
    {
314
        // phpcs:enable
315
        global $conf;
316
317
        $rowcount = $this->workbook->getActiveSheet()->getHighestDataRow();
318
        if ($this->record > $rowcount) {
319
            return false;
320
        }
321
        $array = array();
322
        $xlsx = new Xlsx();
323
        $info = $xlsx->listWorksheetinfo($this->file);
324
        $countcolumns = $info[0]['totalColumns'];
325
        for ($col = 1; $col <= $countcolumns; $col++) {
326
            $val = $this->workbook->getActiveSheet()->getCellByColumnAndRow($col, $this->record)->getValue();
327
            $array[$col]['val'] = $val;
328
            $array[$col]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we consider it null
329
        }
330
        $this->record++;
331
        return $array;
332
    }
333
334
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
335
336
    /**
337
     *  Close file handle
338
     *
339
     * @return integer
340
     */
341
    public function import_close_file()
342
    {
343
        // phpcs:enable
344
        $this->workbook->disconnectWorksheets();
345
        unset($this->workbook);
346
        return 0;
347
    }
348
349
350
    // What is this doing here ? it is common to all imports, is should be in the parent class
351
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
352
    /**
353
     * Insert a record into database
354
     *
355
     * @param array $arrayrecord Array of read values: [fieldpos] => (['val']=>val, ['type']=>-1=null,0=blank,1=string), [fieldpos+1]...
356
     * @param array $array_match_file_to_database Array of target fields where to insert data: [fieldpos] => 's.fieldname', [fieldpos+1]...
357
     * @param Object $objimport Object import (contains objimport->array_import_tables, objimport->array_import_fields, objimport->array_import_convertvalue, ...)
358
     * @param int $maxfields Max number of fields to use
359
     * @param string $importid Import key
360
     * @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.
361
     * @return  int                                     Return integer <0 if KO, >0 if OK
362
     */
363
    public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
364
    {
365
        // phpcs:enable
366
        global $langs, $conf, $user;
367
        global $thirdparty_static; // Specific to thirdparty import
368
        global $tablewithentity_cache; // Cache to avoid to call  desc at each rows on tables
369
370
        $error = 0;
371
        $warning = 0;
372
        $this->errors = array();
373
        $this->warnings = array();
374
375
        //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
376
377
        //var_dump($array_match_file_to_database);
378
        //var_dump($arrayrecord); exit;
379
380
        $array_match_database_to_file = array_flip($array_match_file_to_database);
381
        $sort_array_match_file_to_database = $array_match_file_to_database;
382
        ksort($sort_array_match_file_to_database);
383
384
        //var_dump($sort_array_match_file_to_database);
385
386
        if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[1]['val']))) {
387
            //print 'W';
388
            $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
389
            $this->warnings[$warning]['type'] = 'EMPTY';
390
            $warning++;
391
        } else {
392
            $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)
393
            $updatedone = false;
394
            $insertdone = false;
395
            // For each table to insert, me make a separate insert
396
            foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
397
                // Build sql request
398
                $sql = '';
399
                $listfields = array();
400
                $listvalues = array();
401
                $i = 0;
402
                $errorforthistable = 0;
403
404
                // Define $tablewithentity_cache[$tablename] if not already defined
405
                if (!isset($tablewithentity_cache[$tablename])) {   // keep this test with "isset"
406
                    dol_syslog("Check if table " . $tablename . " has an entity field");
407
                    $resql = $this->db->DDLDescTable($tablename, 'entity');
408
                    if ($resql) {
409
                        $obj = $this->db->fetch_object($resql);
410
                        if ($obj) {
411
                            $tablewithentity_cache[$tablename] = 1; // table contains entity field
412
                        } else {
413
                            $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
414
                        }
415
                    } else {
416
                        dol_print_error($this->db);
417
                    }
418
                } else {
419
                    //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
420
                }
421
422
                // Define array to convert fields ('c.ref', ...) into column index (1, ...)
423
                $arrayfield = array();
424
                foreach ($sort_array_match_file_to_database as $key => $val) {
425
                    $arrayfield[$val] = ($key);
426
                }
427
428
                // $arrayrecord start at key 1
429
                // $sort_array_match_file_to_database start at key 1
430
431
                // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
432
                foreach ($sort_array_match_file_to_database as $key => $val) {
433
                    $fieldalias = preg_replace('/\..*$/i', '', $val);
434
                    $fieldname = preg_replace('/^.*\./i', '', $val);
435
436
                    if ($alias != $fieldalias) {
437
                        continue; // Not a field of current table
438
                    }
439
440
                    if ($key <= $maxfields) {
441
                        // Set $newval with value to insert and set $listvalues with sql request part for insert
442
                        $newval = '';
443
                        if ($arrayrecord[($key)]['type'] > 0) {
444
                            $newval = $arrayrecord[($key)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
445
                        }
446
447
                        //var_dump($newval);var_dump($val);
448
                        //var_dump($objimport->array_import_convertvalue[0][$val]);
449
450
                        // Make some tests on $newval
451
452
                        // Is it a required field ?
453
                        if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string)$newval == '')) {
454
                            $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', num2Alpha($key - 1));
455
                            $this->errors[$error]['type'] = 'NOTNULL';
456
                            $errorforthistable++;
457
                            $error++;
458
                        } else {
459
                            // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
460
                            // We convert field if required
461
                            if (!empty($objimport->array_import_convertvalue[0][$val])) {
462
                                //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
463
                                if (
464
                                    $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
465
                                    || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
466
                                    || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
467
                                ) {
468
                                    // 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.
469
                                    $isidorref = 'id';
470
                                    if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
471
                                        $isidorref = 'ref';
472
                                    }
473
                                    $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
474
                                    //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
475
476
                                    if ($isidorref == 'ref') {    // If value into input import file is a ref, we apply the function defined into descriptor
477
                                        $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
478
                                        $class = $objimport->array_import_convertvalue[0][$val]['class'];
479
                                        $method = $objimport->array_import_convertvalue[0][$val]['method'];
480
                                        if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] != '') {
481
                                            $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval];
482
                                        } else {
483
                                            $resultload = dol_include_once($file);
484
                                            if (empty($resultload)) {
485
                                                dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
486
                                                break;
487
                                            }
488
                                            $classinstance = new $class($this->db);
489
                                            if ($class == 'CGenericDic') {
490
                                                $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
491
                                                $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
492
                                            }
493
494
                                            // Try the fetch from code or ref
495
                                            $param_array = array('', $newval);
496
                                            if ($class == 'AccountingAccount') {
497
                                                //var_dump($arrayrecord[0]['val']);
498
                                                /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
499
                                                $tmpchartofaccount = new AccountancySystem($this->db);
500
                                                $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
501
                                                //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
502
                                                if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
503
                                                {
504
                                                    $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
505
                                                    $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
506
                                                    $errorforthistable++;
507
                                                    $error++;
508
                                                }*/
509
                                                $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
510
                                            }
511
512
                                            $result = call_user_func_array(array($classinstance, $method), $param_array);
513
514
                                            // If duplicate record found
515
                                            if (!($classinstance->id != '') && $result == -2) {
516
                                                $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
517
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
518
                                                $errorforthistable++;
519
                                                $error++;
520
                                            }
521
522
                                            // If not found, try the fetch from label
523
                                            if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
524
                                                $param_array = array('', '', $newval);
525
                                                call_user_func_array(array($classinstance, $method), $param_array);
526
                                            }
527
                                            $this->cacheconvert[$file . '_' . $class . '_' . $method . '_'][$newval] = $classinstance->id;
528
529
                                            //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
530
                                            if ($classinstance->id != '') { // id may be 0, it is a found value
531
                                                $newval = $classinstance->id;
532
                                            } elseif (!$error) {
533
                                                if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
534
                                                    // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
535
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
536
                                                } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
537
                                                    // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
538
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', $key, $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
539
                                                } else {
540
                                                    $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
541
                                                }
542
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
543
                                                $errorforthistable++;
544
                                                $error++;
545
                                            }
546
                                        }
547
                                    }
548
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
549
                                    $isidorref = 'id';
550
                                    if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
551
                                        $isidorref = 'ref';
552
                                    }
553
                                    $newval = preg_replace('/^(id|ref):/i', '', $newval);
554
555
                                    if ($isidorref == 'ref') {
556
                                        $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
557
                                        $class = $objimport->array_import_convertvalue[0][$val]['class'];
558
                                        $method = $objimport->array_import_convertvalue[0][$val]['method'];
559
                                        $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
560
                                        $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
561
                                        if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] != '') {
562
                                            $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval];
563
                                        } else {
564
                                            $resultload = dol_include_once($file);
565
                                            if (empty($resultload)) {
566
                                                dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', code=' . $code);
567
                                                break;
568
                                            }
569
                                            $classinstance = new $class($this->db);
570
                                            // Try the fetch from code and ref
571
                                            $param_array = array('', $newval, $code);
572
                                            call_user_func_array(array($classinstance, $method), $param_array);
573
                                            $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $code][$newval] = $classinstance->id;
574
                                            if ($classinstance->id > 0) {    // we found record
575
                                                $newval = $classinstance->id;
576
                                            } else {
577
                                                if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
578
                                                    // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
579
                                                    $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
580
                                                } else {
581
                                                    $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
582
                                                }
583
                                                $this->errors[$error]['type'] = 'FOREIGNKEY';
584
                                                $errorforthistable++;
585
                                                $error++;
586
                                            }
587
                                        }
588
                                    }
589
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
590
                                    if (empty($newval)) {
591
                                        $newval = '0';
592
                                    }
593
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
594
                                    $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
595
                                    $class = $objimport->array_import_convertvalue[0][$val]['class'];
596
                                    $method = $objimport->array_import_convertvalue[0][$val]['method'];
597
                                    $units = $objimport->array_import_convertvalue[0][$val]['units'];
598
                                    if ($this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] != '') {
599
                                        $newval = $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval];
600
                                    } else {
601
                                        $resultload = dol_include_once($file);
602
                                        if (empty($resultload)) {
603
                                            dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method . ', units=' . $units);
604
                                            break;
605
                                        }
606
                                        $classinstance = new $class($this->db);
607
                                        // Try the fetch from code or ref
608
                                        call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
609
                                        $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
610
                                        $this->cacheconvert[$file . '_' . $class . '_' . $method . '_' . $units][$newval] = $scaleorid;
611
                                        //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
612
                                        if ($classinstance->id > 0) {   // we found record
613
                                            $newval = $scaleorid ? $scaleorid : 0;
614
                                        } else {
615
                                            if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
616
                                                // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
617
                                                $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', $key, $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
618
                                            } else {
619
                                                $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
620
                                            }
621
                                            $this->errors[$error]['type'] = 'FOREIGNKEY';
622
                                            $errorforthistable++;
623
                                            $error++;
624
                                        }
625
                                    }
626
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
627
                                    if (strtolower($newval) == 'auto') {
628
                                        $this->thirdpartyobject->get_codeclient(0, 0);
629
                                        $newval = $this->thirdpartyobject->code_client;
630
                                        //print 'code_client='.$newval;
631
                                    }
632
                                    if (empty($newval)) {
633
                                        $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
634
                                    }
635
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
636
                                    if (strtolower($newval) == 'auto') {
637
                                        $this->thirdpartyobject->get_codefournisseur(0, 1);
638
                                        $newval = $this->thirdpartyobject->code_fournisseur;
639
                                        //print 'code_fournisseur='.$newval;
640
                                    }
641
                                    if (empty($newval)) {
642
                                        $arrayrecord[($key)]['type'] = -1; // If we get empty value, we will use "null"
643
                                    }
644
                                } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
645
                                    if (strtolower($newval) == 'auto') {
646
                                        $this->thirdpartyobject->get_codecompta('customer');
647
                                        $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

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