dolibarr 24.0.0-beta
modules_import.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
27require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
28
29
34{
38 public $db;
39
43 public $datatoimport;
44
48 public $error = '';
49
53 public $errors = array();
54
58 public $warnings = array();
59
63 public $id;
64
68 public $label;
69
73 public $extension;
74
79 public $version = 'dolibarr';
80
85 public $phpmin = array(7, 0);
86
91 public $label_lib;
92
97 public $version_lib;
98
99 // Array of all drivers
103 public $driverlabel = array();
104
108 public $driverdesc = array();
109
113 public $driverversion = array();
114
118 public $drivererror = array();
119
123 public $liblabel = array();
124
128 public $libversion = array();
129
133 public $charset;
134
138 public $picto;
139
143 public $desc;
144
148 public $escape;
149
153 public $enclosure;
154
158 public $thirdpartyobject;
159
167 public $importtriggermode = '';
168
176 public $importissimulation = 0;
177
183 public $importtriggerinterface;
184
190 public $importbulkstats = array();
191
197 public $importtriggerobjectprototypes = array();
198
204 public $importtriggeractionshookcache = array();
205
211 public $cacheconvert = array();
212
218 public $cachefieldtable = array();
219
225 public $nbinsert = 0;
226
232 public $nbupdate = 0;
233
237 public static $mapTableToElement = MODULE_MAPPING;
238
242 public function __construct()
243 {
244 global $hookmanager;
245
246 if (is_object($hookmanager)) {
247 $hookmanager->initHooks(array('import'));
248 $parameters = array();
249 $reshook = $hookmanager->executeHooks('constructModeleImports', $parameters, $this);
250 if ($reshook >= 0 && !empty($hookmanager->resArray)) {
251 foreach ($hookmanager->resArray as $mapList) {
252 self::$mapTableToElement[$mapList['table']] = $mapList['element'];
253 }
254 }
255 }
256 }
257
263 public function getDriverId()
264 {
265 return $this->id;
266 }
267
273 public function getDriverLabel()
274 {
275 return $this->label;
276 }
277
283 public function getDriverDesc()
284 {
285 return $this->desc;
286 }
287
293 public function getDriverExtension()
294 {
295 return $this->extension;
296 }
297
303 public function getDriverVersion()
304 {
305 return $this->version;
306 }
307
313 public function getLibLabel()
314 {
315 return $this->label_lib;
316 }
317
323 public function getLibVersion()
324 {
325 return $this->version_lib;
326 }
327
328
336 public function listOfAvailableImportFormat($db, $maxfilenamelength = 0)
337 {
338 dol_syslog(get_class($this)."::listOfAvailableImportFormat");
339
340 $dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
341 $handle = opendir($dir);
342
343 // Search list ov drivers available and qualified
344 if (is_resource($handle)) {
345 while (($file = readdir($handle)) !== false) {
346 $reg = array();
347 if (preg_match("/^import_(.*)\.modules\.php/i", $file, $reg)) {
348 $moduleid = $reg[1];
349
350 // Loading Class
351 $file = $dir."/import_".$moduleid.".modules.php";
352 $classname = "Import".ucfirst($moduleid);
353
354 require_once $file;
355 $module = new $classname($db, '');
356 '@phan-var-force ModeleImports $module';
357
358 // Picto
359 $this->picto[$module->id] = $module->picto;
360 // Driver properties
361 $this->driverlabel[$module->id] = $module->getDriverLabel();
362 $this->driverdesc[$module->id] = $module->getDriverDesc();
363 $this->driverversion[$module->id] = $module->getDriverVersion();
364 $this->drivererror[$module->id] = $module->error ? $module->error : '';
365 // If use an external lib
366 $this->liblabel[$module->id] = ($module->error ? '<span class="error">'.$module->error.'</span>' : $module->getLibLabel());
367 $this->libversion[$module->id] = $module->getLibVersion();
368 }
369 }
370 }
371
372 return array_keys($this->driverlabel);
373 }
374
375
382 public function getPictoForKey($key)
383 {
384 return $this->picto[$key];
385 }
386
393 public function getDriverLabelForKey($key)
394 {
395 return $this->driverlabel[$key];
396 }
397
404 public function getDriverDescForKey($key)
405 {
406 return $this->driverdesc[$key];
407 }
408
415 public function getDriverVersionForKey($key)
416 {
417 return $this->driverversion[$key];
418 }
419
426 public function getLibLabelForKey($key)
427 {
428 return $this->liblabel[$key];
429 }
430
437 public function getLibVersionForKey($key)
438 {
439 return $this->libversion[$key];
440 }
441
448 public function getElementFromTableWithPrefix($tableNameWithPrefix)
449 {
450 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', $tableNameWithPrefix);
451 $element = $tableElement;
452
453 if (isset(self::$mapTableToElement[$tableElement])) {
454 $element = self::$mapTableToElement[$tableElement];
455 }
456
457 return $element;
458 }
459
465 protected function getImportTriggerMode()
466 {
467 $mode = trim((string) $this->importtriggermode);
468 if ($mode === '') {
469 $mode = (string) getDolGlobalString('IMPORT_TRIGGER_MODE_DEFAULT', 'strict_line');
470 }
471 if (!in_array($mode, array('strict_line', 'fast_bulk'), true)) {
472 $mode = 'strict_line';
473 }
474 return $mode;
475 }
476
484 protected function registerImportBulkEvent($tablename, $operation)
485 {
486 if (empty($this->importbulkstats)) {
487 $this->importbulkstats = array(
488 'insert' => 0,
489 'update' => 0,
490 'tables' => array(),
491 );
492 }
493
494 $operation = strtolower((string) $operation);
495 if (!isset($this->importbulkstats[$operation])) {
496 $this->importbulkstats[$operation] = 0;
497 }
498 $this->importbulkstats[$operation]++;
499
500 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', (string) $tablename);
501 if (!isset($this->importbulkstats['tables'][$tableElement])) {
502 $this->importbulkstats['tables'][$tableElement] = array('insert' => 0, 'update' => 0);
503 }
504 if (!isset($this->importbulkstats['tables'][$tableElement][$operation])) {
505 $this->importbulkstats['tables'][$tableElement][$operation] = 0;
506 }
507 $this->importbulkstats['tables'][$tableElement][$operation]++;
508 }
509
519 public function runImportBulkTrigger($importid, $user, $langs, $conf)
520 {
521 require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
522
523 if (!($this->importtriggerinterface instanceof Interfaces)) {
524 $this->importtriggerinterface = new Interfaces($this->db);
525 }
526
527 $object = new stdClass();
528 $object->db = $this->db;
529 $object->id = 0;
530 $object->rowid = 0;
531 $object->import_key = $importid;
532 $object->context = array(
533 'import' => 1,
534 'operation' => 'bulk',
535 'importtriggermode' => $this->getImportTriggerMode(),
536 );
537 $object->bulk_stats = (empty($this->importbulkstats) ? array('insert' => 0, 'update' => 0, 'tables' => array()) : $this->importbulkstats);
538
539 try {
540 $result = $this->importtriggerinterface->run_triggers('IMPORT_BULK_DONE', $object, $user, $langs, $conf);
541 } catch (Throwable $e) {
542 $this->errors[] = array('lib' => $e->getMessage(), 'type' => 'TRIGGER');
543 $this->error = 'ErrorFailedTriggerCall';
544 return -1;
545 }
546
547 if ($result < 0) {
548 if (!empty($this->importtriggerinterface->errors)) {
549 foreach ($this->importtriggerinterface->errors as $errormsg) {
550 $this->errors[] = array('lib' => $errormsg, 'type' => 'TRIGGER');
551 }
552 }
553 $this->error = 'ErrorFailedTriggerCall';
554 return -1;
555 }
556
557 return 1;
558 }
559
569 protected function getImportTriggerActions($tableElement, $operation, $element, $object = null)
570 {
571 $operation = strtolower((string) $operation);
572
573 $actionMap = array(
574 'societe' => array('insert' => 'COMPANY_CREATE', 'update' => 'COMPANY_MODIFY'),
575 'product' => array('insert' => 'PRODUCT_CREATE', 'update' => 'PRODUCT_MODIFY'),
576 'socpeople' => array('insert' => 'CONTACT_CREATE', 'update' => 'CONTACT_MODIFY'),
577 'commande' => array('insert' => 'ORDER_CREATE', 'update' => 'ORDER_MODIFY'),
578 'commandedet' => array('insert' => 'LINEORDER_INSERT', 'update' => 'LINEORDER_MODIFY'),
579 'propal' => array('insert' => 'PROPAL_CREATE', 'update' => 'PROPAL_MODIFY'),
580 'propaldet' => array('insert' => 'LINEPROPAL_INSERT', 'update' => 'LINEPROPAL_MODIFY'),
581 'facture' => array('insert' => 'BILL_CREATE', 'update' => 'BILL_MODIFY'),
582 'facturedet' => array('insert' => 'LINEBILL_INSERT', 'update' => 'LINEBILL_MODIFY'),
583 'facture_fourn' => array('insert' => 'BILL_SUPPLIER_CREATE', 'update' => 'BILL_SUPPLIER_MODIFY'),
584 'facture_fourn_det' => array('insert' => 'LINEBILL_SUPPLIER_CREATE', 'update' => 'LINEBILL_SUPPLIER_MODIFY'),
585 'commande_fournisseur' => array('insert' => 'ORDER_SUPPLIER_CREATE', 'update' => 'ORDER_SUPPLIER_MODIFY'),
586 'commande_fournisseurdet' => array('insert' => 'LINEORDER_SUPPLIER_CREATE', 'update' => 'LINEORDER_SUPPLIER_MODIFY'),
587 'contrat' => array('insert' => 'CONTRACT_CREATE', 'update' => 'CONTRACT_MODIFY'),
588 'contratdet' => array('insert' => 'LINECONTRACT_INSERT', 'update' => 'LINECONTRACT_MODIFY'),
589 'fichinter' => array('insert' => 'FICHINTER_CREATE', 'update' => 'FICHINTER_MODIFY'),
590 'fichinterdet' => array('insert' => 'LINEFICHINTER_CREATE', 'update' => 'LINEFICHINTER_MODIFY'),
591 'expedition' => array('insert' => 'SHIPPING_CREATE', 'update' => 'SHIPPING_MODIFY'),
592 'expeditiondet' => array('insert' => 'LINESHIPPING_INSERT', 'update' => 'LINESHIPPING_MODIFY'),
593 'supplier_proposal' => array('insert' => 'SUPPLIER_PROPOSAL_CREATE', 'update' => 'SUPPLIER_PROPOSAL_MODIFY'),
594 'supplier_proposaldet' => array('insert' => 'LINESUPPLIER_PROPOSAL_INSERT', 'update' => 'LINESUPPLIER_PROPOSAL_MODIFY'),
595 );
596
597 $actions = array();
598 if (!empty($actionMap[$tableElement][$operation])) {
599 $actions[] = $actionMap[$tableElement][$operation];
600 }
601
602 // Let external modules add explicit import trigger actions.
603 // We merge with core mapping when present.
604 $hookactions = $this->getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object);
605 if (!empty($hookactions)) {
606 $actions = array_merge($actions, $hookactions);
607 }
608
609 // Dynamic fallback only for real business objects and only when
610 // no explicit mapping/hook action exists.
611 // Avoid generating trigger names from stdClass (legacy SQL context).
612 if (empty($actions) && is_object($object) && method_exists($object, 'call_trigger')) {
613 $triggerprefix = $this->getImportTriggerPrefixFromObject($object);
614 $action = $this->buildImportTriggerActionFromPrefix($triggerprefix, $operation);
615 if (!empty($action)) {
616 $actions[] = $action;
617 }
618 }
619
620 // Generic fallback for external/custom objects imported through legacy SQL path:
621 // derive a deterministic trigger prefix from element/table when no explicit mapping exists.
622 if (empty($actions)) {
623 $triggerprefix = $this->getImportGenericTriggerPrefix($element, $tableElement);
624 $action = $this->buildImportTriggerActionFromPrefix($triggerprefix, $operation);
625 if (!empty($action)) {
626 $actions[] = $action;
627 }
628 }
629
630 return array_values(array_unique(array_filter($actions)));
631 }
632
640 protected function buildImportTriggerActionFromPrefix($triggerprefix, $operation)
641 {
642 $triggerprefix = strtoupper(trim((string) $triggerprefix));
643 $operation = strtolower((string) $operation);
644 if ($triggerprefix === '') {
645 return '';
646 }
647
648 if ($operation === 'update') {
649 return $triggerprefix.'_MODIFY';
650 }
651 if ($operation === 'insert') {
652 return preg_match('/^LINE/', $triggerprefix) ? $triggerprefix.'_INSERT' : $triggerprefix.'_CREATE';
653 }
654
655 return '';
656 }
657
665 {
666 if (!empty($object->TRIGGER_PREFIX)) {
667 return (string) $object->TRIGGER_PREFIX;
668 }
669 if (!empty($object->element)) {
670 return (string) $object->element;
671 }
672 return get_class($object);
673 }
674
682 protected function getImportGenericTriggerPrefix($element, $tableElement)
683 {
684 $rawprefix = '';
685 if (!empty($element)) {
686 $rawprefix = (string) $element;
687 } elseif (!empty($tableElement)) {
688 $rawprefix = (string) $tableElement;
689 }
690
691 return trim((string) preg_replace('/[^A-Za-z0-9]+/', '_', strtoupper($rawprefix)), '_');
692 }
693
711 protected function getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object = null)
712 {
713 global $hookmanager;
714
715 $actions = array();
716 $objectclass = (is_object($object) ? get_class($object) : 'none');
717 $cachekey = $tableElement.'|'.$operation.'|'.$element.'|'.$objectclass;
718 if (isset($this->importtriggeractionshookcache[$cachekey])) {
719 return $this->importtriggeractionshookcache[$cachekey];
720 }
721
722 if (!is_object($hookmanager)) {
723 $this->importtriggeractionshookcache[$cachekey] = $actions;
724 return $actions;
725 }
726
727 $hookmanager->initHooks(array('import'));
728 $parameters = array(
729 'tableelement' => (string) $tableElement,
730 'operation' => (string) $operation,
731 'element' => (string) $element,
732 );
733 $action = '';
734 $hookmanager->executeHooks('getImportTriggerActions', $parameters, $object, $action);
735
736 if (!empty($hookmanager->resArray['actions'])) {
737 if (is_array($hookmanager->resArray['actions'])) {
738 $actions = array_merge($actions, $hookmanager->resArray['actions']);
739 } else {
740 $actions = array_merge($actions, preg_split('/[\s,;|]+/', (string) $hookmanager->resArray['actions']));
741 }
742 }
743 if (!empty($hookmanager->resArray['action'])) {
744 $actions[] = (string) $hookmanager->resArray['action'];
745 }
746
747 $cleaned = array();
748 foreach ($actions as $oneaction) {
749 $oneaction = strtoupper(trim((string) $oneaction));
750 if ($oneaction !== '') {
751 $cleaned[] = $oneaction;
752 }
753 }
754
755 $cleaned = array_values(array_unique($cleaned));
756 $this->importtriggeractionshookcache[$cachekey] = $cleaned;
757 return $cleaned;
758 }
759
772 protected function triggerImportSqlOperation($tablename, $operation, $rowid, $importid, $user, $langs, $conf)
773 {
774 require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
775
776 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', $tablename);
777 $element = $this->getElementFromTableWithPrefix($tablename);
778 $object = null;
779 $needenrichobject = (bool) getDolGlobalInt('IMPORT_TRIGGER_ENRICH_OBJECT');
780
781 // Fast-path: for mapped tables, get action list without loading business object.
782 $actions = $this->getImportTriggerActions($tableElement, $operation, $element, null);
783
784 // Resolve business object only when needed:
785 // - dynamic action fallback requires real object,
786 // - optional richer trigger context can be enabled with IMPORT_TRIGGER_ENRICH_OBJECT.
787 if (empty($actions) || $needenrichobject) {
788 // Try to resolve a real business object for full trigger compatibility.
789 // - with rowid when available (best case),
790 // - otherwise as a prototype object based on element/table.
791 if ((int) $rowid > 0) {
792 $objecttmp = fetchObjectByElement((int) $rowid, $tableElement);
793 if (is_object($objecttmp)) {
794 $object = $objecttmp;
795 }
796 }
797 if (!is_object($object)) {
798 $objecttmp = fetchObjectByElement(0, $tableElement);
799 if (is_object($objecttmp)) {
800 $object = $objecttmp;
801 if ((int) $rowid > 0) {
802 if (method_exists($object, 'fetch')) {
803 $fetchres = $object->fetch((int) $rowid);
804 if ($fetchres <= 0) {
805 $object->id = (int) $rowid;
806 $object->rowid = (int) $rowid;
807 }
808 } else {
809 $object->id = (int) $rowid;
810 $object->rowid = (int) $rowid;
811 }
812 }
813 }
814 }
815 }
816
817 // Compatibility path for strict_line mode:
818 // for mapped actions, provide at least a business object prototype (not stdClass)
819 // so custom triggers can call object methods safely.
820 if (!is_object($object) && !empty($actions) && $this->getImportTriggerMode() === 'strict_line') {
821 if (!isset($this->importtriggerobjectprototypes[$tableElement])) {
822 $prototype = fetchObjectByElement(0, $tableElement);
823 if (is_object($prototype)) {
824 $this->importtriggerobjectprototypes[$tableElement] = $prototype;
825 }
826 }
827 if (isset($this->importtriggerobjectprototypes[$tableElement])) {
828 $object = clone $this->importtriggerobjectprototypes[$tableElement];
829 $object->id = (int) $rowid;
830 $object->rowid = (int) $rowid;
831 if ((int) $rowid > 0 && method_exists($object, 'fetch')) {
832 $fetchres = $object->fetch((int) $rowid);
833 if ($fetchres <= 0) {
834 $object->id = (int) $rowid;
835 $object->rowid = (int) $rowid;
836 }
837 }
838 }
839 }
840
841 if (!is_object($object)) {
842 $object = new stdClass();
843 $object->db = $this->db;
844 $object->id = (int) $rowid;
845 $object->rowid = (int) $rowid;
846 $object->table_element = $tableElement;
847 $object->element = $element;
848 }
849 $object->import_key = $importid;
850 $object->context = array('import' => 1, 'operation' => $operation);
851
852 if (empty($actions)) {
853 $actions = $this->getImportTriggerActions($tableElement, $operation, $element, $object);
854 }
855
856 if (empty($actions)) {
857 dol_syslog(get_class($this)."::triggerImportSqlOperation no trigger mapping for table=".$tableElement." operation=".$operation, LOG_DEBUG);
858 return 1;
859 }
860
861 // Optional enrichment: provides full row payload for stdClass context.
862 // Disabled by default for performance.
863 if ($needenrichobject && $rowid > 0 && $object instanceof stdClass) {
864 $sql = "SELECT * FROM ".$tablename." WHERE rowid = ".((int) $rowid);
865 $resql = $this->db->query($sql);
866 if ($resql) {
867 $objrow = $this->db->fetch_object($resql);
868 if ($objrow) {
869 foreach (get_object_vars($objrow) as $key => $value) {
870 $object->$key = $value;
871 }
872 if (!isset($object->id) && isset($object->rowid)) {
873 $object->id = (int) $object->rowid;
874 }
875 }
876 }
877 }
878
879 if (!($this->importtriggerinterface instanceof Interfaces)) {
880 $this->importtriggerinterface = new Interfaces($this->db);
881 }
882 $interface = $this->importtriggerinterface;
883 foreach ($actions as $action) {
884 try {
885 $result = $interface->run_triggers($action, $object, $user, $langs, $conf);
886 } catch (Throwable $e) {
887 $this->errors[] = array('lib' => $e->getMessage(), 'type' => 'TRIGGER');
888 $this->error = 'ErrorFailedTriggerCall';
889 return -1;
890 }
891 if ($result < 0) {
892 if (!empty($interface->errors)) {
893 foreach ($interface->errors as $errormsg) {
894 $this->errors[] = array('lib' => $errormsg, 'type' => 'TRIGGER');
895 }
896 }
897 $this->error = 'ErrorFailedTriggerCall';
898 return -1;
899 }
900 }
901
902 return 1;
903 }
904
905 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
912 public function import_open_file($file)
913 {
914 // phpcs:enable
915 $msg = get_class($this)."::".__FUNCTION__." not implemented";
916 dol_syslog($msg, LOG_ERR);
917 $this->errors[] = $msg;
918 $this->error = $msg;
919 return -1;
920 }
921
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
930 public function import_get_nb_of_lines($file)
931 {
932 // phpcs:enable
933 $msg = get_class($this)."::".__FUNCTION__." not implemented";
934 dol_syslog($msg, LOG_ERR);
935 $this->errors[] = $msg;
936 $this->error = $msg;
937 return -1;
938 }
939
940 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
946 public function import_read_header()
947 {
948 // phpcs:enable
949 $msg = get_class($this)."::".__FUNCTION__." not implemented";
950 dol_syslog($msg, LOG_ERR);
951 $this->errors[] = $msg;
952 $this->error = $msg;
953 return -1;
954 }
955
956
957 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
963 public function import_read_record()
964 {
965 // phpcs:enable
966 $msg = get_class($this)."::".__FUNCTION__." not implemented";
967 dol_syslog($msg, LOG_ERR);
968 $this->errors[] = $msg;
969 $this->error = $msg;
970 return array();
971 }
972
973
974 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
980 public function import_close_file()
981 {
982 // phpcs:enable
983 $msg = get_class($this)."::".__FUNCTION__." not implemented";
984 dol_syslog($msg, LOG_ERR);
985 $this->errors[] = $msg;
986 $this->error = $msg;
987 return -1;
988 }
989
1002 protected function commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, $recordpositionbase = 0)
1003 {
1004 global $langs, $conf, $user;
1005 global $thirdparty_static; // Specific to thirdparty import
1006 global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
1007
1008 if (is_array($arrayrecord) && !empty($recordpositionbase)) {
1009 $arrayrecord = array_values($arrayrecord);
1010 }
1011
1012 $error = 0;
1013 $warning = 0;
1014 $importtriggermode = $this->getImportTriggerMode();
1015 $importissimulation = !empty($this->importissimulation);
1016 $this->errors = array();
1017 $this->warnings = array();
1018
1019 //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
1020
1021 //var_dump($array_match_file_to_database);
1022 //var_dump($arrayrecord); exit;
1023
1024 $array_match_database_to_file = array_flip($array_match_file_to_database);
1025 $sort_array_match_file_to_database = $array_match_file_to_database;
1026 ksort($sort_array_match_file_to_database);
1027
1028 //var_dump($sort_array_match_file_to_database);
1029
1030 if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
1031 //print 'W';
1032 $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
1033 $this->warnings[$warning]['type'] = 'EMPTY';
1034 $warning++;
1035 } else {
1036 $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)
1037 $updatedone = false;
1038 $insertdone = false;
1039 // For each table to insert, me make a separate insert
1040 foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
1041 // Build sql request
1042 $sql = '';
1043 $listfields = array();
1044 $listvalues = array();
1045 $i = 0;
1046 $errorforthistable = 0;
1047
1048 // Define $tablewithentity_cache[$tablename] if not already defined
1049 if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
1050 dol_syslog("Check if table ".$tablename." has an entity field");
1051 $resql = $this->db->DDLDescTable($tablename, 'entity');
1052 if ($resql) {
1053 $obj = $this->db->fetch_object($resql);
1054 if ($obj) {
1055 $tablewithentity_cache[$tablename] = 1; // table contains entity field
1056 } else {
1057 $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
1058 }
1059 } else {
1060 dol_print_error($this->db);
1061 }
1062 } else {
1063 //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
1064 }
1065
1066 // Define an array to convert fields ('c.ref', ...) into column index (1, ...)
1067 $arrayfield = array();
1068 foreach ($sort_array_match_file_to_database as $key => $val) {
1069 $arrayfield[$val] = ($key - 1);
1070 }
1071
1072 // $arrayrecord start at key 0
1073 // $sort_array_match_file_to_database start at key 1
1074
1075 // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
1076 foreach ($sort_array_match_file_to_database as $key => $val) {
1077 $fieldalias = preg_replace('/\..*$/i', '', $val);
1078 $fieldname = preg_replace('/^.*\./i', '', $val);
1079
1080 if ($alias != $fieldalias) {
1081 continue; // Not a field of current table
1082 }
1083
1084 if ($key <= $maxfields) {
1085 // Set $newval with value to insert and set $listvalues with sql request part for insert
1086 $newval = '';
1087 if ($arrayrecord[($key - 1)]['type'] > 0) {
1088 $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
1089 }
1090
1091 //var_dump($newval);var_dump($val);
1092 //var_dump($objimport->array_import_convertvalue[0][$val]);
1093
1094 // Make some tests on $newval
1095
1096 // Is it a required field ?
1097 if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
1098 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
1099 $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
1100 $this->errors[$error]['type'] = 'NOTNULL';
1101 $errorforthistable++;
1102 $error++;
1103 } else {
1104 // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
1105 // We convert field if required
1106 if (!empty($objimport->array_import_convertvalue[0][$val])) {
1107 //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
1108 if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
1109 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
1110 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
1111 ) {
1112 // 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.
1113 $isidorref = 'id';
1114 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
1115 $isidorref = 'ref';
1116 }
1117
1118 $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
1119 //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
1120
1121 if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
1122 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1123 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1124 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1125 $cachekey = $file.'_'.$class.'_'.$method.'_';
1126 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1127 $newval = $this->cacheconvert[$cachekey][$newval];
1128 } else {
1129 $resultload = dol_include_once($file);
1130 if (empty($resultload)) {
1131 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
1132 break;
1133 }
1134 $classinstance = new $class($this->db);
1135 if ($class == 'CGenericDic') {
1136 $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
1137 $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
1138 }
1139
1140 // Try the fetch from code or ref
1141 $param_array = array('', $newval);
1142 if ($class == 'AccountingAccount') {
1143 //var_dump($arrayrecord[0]['val']);
1144 /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
1145 $tmpchartofaccount = new AccountancySystem($this->db);
1146 $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
1147 //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
1148 if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
1149 {
1150 $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
1151 $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
1152 $errorforthistable++;
1153 $error++;
1154 }*/
1155 $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
1156 }
1157 if ($class == 'CActionComm') {
1158 $param_array = array($newval); // CActionComm fetch method have same parameter for id and code
1159 }
1160 $result = call_user_func_array(array($classinstance, $method), $param_array);
1161
1162 // If duplicate record found
1163 if (!($classinstance->id != '') && $result == -2) {
1164 $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
1165 $this->errors[$error]['type'] = 'FOREIGNKEY';
1166 $errorforthistable++;
1167 $error++;
1168 }
1169
1170 // If not found, try the fetch from label
1171 if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
1172 $param_array = array('', '', $newval);
1173 call_user_func_array(array($classinstance, $method), $param_array);
1174 }
1175 $this->cacheconvert[$cachekey][$newval] = $classinstance->id;
1176
1177 //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
1178 if ($classinstance->id != '') { // id may be 0, it is a found value
1179 $newval = $classinstance->id;
1180 } elseif (! $error) {
1181 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1182 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1183 } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
1184 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
1185 } else {
1186 $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
1187 }
1188 $this->errors[$error]['type'] = 'FOREIGNKEY';
1189 $errorforthistable++;
1190 $error++;
1191 }
1192 }
1193 }
1194 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
1195 $isidorref = 'id';
1196 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
1197 $isidorref = 'ref';
1198 }
1199 $newval = preg_replace('/^(id|ref):/i', '', $newval);
1200
1201 if ($isidorref == 'ref') {
1202 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1203 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1204 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1205 $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
1206 $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
1207 $cachekey = $file.'_'.$class.'_'.$method.'_'.$code;
1208 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1209 $newval = $this->cacheconvert[$cachekey][$newval];
1210 } else {
1211 $resultload = dol_include_once($file);
1212 if (empty($resultload)) {
1213 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
1214 break;
1215 }
1216 $classinstance = new $class($this->db);
1217 // Try the fetch from code and ref
1218 $param_array = array('', $newval, $code);
1219 call_user_func_array(array($classinstance, $method), $param_array);
1220 $this->cacheconvert[$cachekey][$newval] = $classinstance->id;
1221 if ($classinstance->id > 0) { // we found record
1222 $newval = $classinstance->id;
1223 } else {
1224 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1225 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1226 } else {
1227 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
1228 }
1229 $this->errors[$error]['type'] = 'FOREIGNKEY';
1230 $errorforthistable++;
1231 $error++;
1232 }
1233 }
1234 }
1235 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
1236 if (empty($newval)) {
1237 $newval = '0';
1238 }
1239 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
1240 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1241 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1242 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1243 $units = $objimport->array_import_convertvalue[0][$val]['units'];
1244 $cachekey = $file.'_'.$class.'_'.$method.'_'.$units;
1245 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1246 $newval = $this->cacheconvert[$cachekey][$newval];
1247 } else {
1248 $resultload = dol_include_once($file);
1249 if (empty($resultload)) {
1250 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
1251 break;
1252 }
1253 $classinstance = new $class($this->db);
1254 // Try the fetch from code or ref
1255 call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
1256 $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
1257 $this->cacheconvert[$cachekey][$newval] = $scaleorid;
1258 //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
1259 if ($classinstance->id > 0) { // we found record
1260 $newval = $scaleorid ? $scaleorid : 0;
1261 } else {
1262 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1263 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1264 } else {
1265 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
1266 }
1267 $this->errors[$error]['type'] = 'FOREIGNKEY';
1268 $errorforthistable++;
1269 $error++;
1270 }
1271 }
1272 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
1273 if (strtolower($newval) == 'auto') {
1274 $this->thirdpartyobject->get_codeclient(null, 0);
1275 $newval = $this->thirdpartyobject->code_client;
1276 //print 'code_client='.$newval;
1277 }
1278 if (empty($newval)) {
1279 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1280 }
1281 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
1282 if (strtolower($newval) == 'auto') {
1283 $this->thirdpartyobject->get_codefournisseur(null, 1);
1284 $newval = $this->thirdpartyobject->code_fournisseur;
1285 //print 'code_fournisseur='.$newval;
1286 }
1287 if (empty($newval)) {
1288 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1289 }
1290 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
1291 if (strtolower($newval) == 'auto') {
1292 $this->thirdpartyobject->get_codecompta('customer');
1293 $newval = $this->thirdpartyobject->code_compta_client;
1294 //print 'code_compta='.$newval;
1295 }
1296 if (empty($newval)) {
1297 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1298 }
1299 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
1300 if (strtolower($newval) == 'auto') {
1301 $this->thirdpartyobject->get_codecompta('supplier');
1302 $newval = $this->thirdpartyobject->code_compta_fournisseur;
1303 if (empty($newval)) {
1304 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1305 }
1306 //print 'code_compta_fournisseur='.$newval;
1307 }
1308 if (empty($newval)) {
1309 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1310 }
1311 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
1312 if (strtolower($newval) == 'auto') {
1313 $defaultref = '';
1314
1315 $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
1316 $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
1317
1318 if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
1319 require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
1320 $modForNumber = new $classModForNumber();
1321 '@phan-var-force ModeleNumRefMembers|ModeleNumRefCommandes|ModeleNumRefSuppliersInvoices|ModeleNumRefSuppliersOrders|ModeleNumRefProjects|ModeleNumRefTask|ModeleNumRefPropales $modForNumber';
1322
1323 $tmpobject = null;
1324 // Set the object with the date property when we can
1325 if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
1326 $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
1327 require_once DOL_DOCUMENT_ROOT.$pathForObject;
1328 $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
1329 $tmpobject = new $tmpclassobject($this->db);
1330 foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>0, ...)
1331 if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
1332 $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
1333 }
1334 }
1335 }
1336
1337 $defaultref = $modForNumber->getNextValue(null, $tmpobject);
1338 }
1339 if (is_numeric($defaultref) && $defaultref <= 0) { // If error
1340 $defaultref = '';
1341 }
1342 $newval = $defaultref;
1343 }
1344 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
1345 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1346 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1347 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1348 $resultload = dol_include_once($file);
1349 if (empty($resultload)) {
1350 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
1351 break;
1352 }
1353 $classinstance = new $class($this->db);
1354 $computedFieldPos = isset($arrayfield[$val]) ? ((int) $arrayfield[$val]) : 0;
1355 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $computedFieldPos));
1356 if (empty($classinstance->error) && empty($classinstance->errors)) {
1357 $newval = $res; // We get new value computed.
1358 } else {
1359 $this->errors[$error]['type'] = 'CLASSERROR';
1360 $this->errors[$error]['lib'] = implode(
1361 "\n",
1362 array_merge([$classinstance->error], $classinstance->errors)
1363 );
1364 $errorforthistable++;
1365 $error++;
1366 }
1367 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
1368 $newval = price2num($newval);
1369 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
1370 if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
1371 $newval = rtrim(trim($newval), "0");
1372 } else {
1373 $newval = trim($newval);
1374 }
1375 }
1376
1377 //print 'Val to use as insert is '.$newval.'<br>';
1378 }
1379
1380 // Test regexp
1381 if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
1382 // If test regex string is "field@table" or "field@table:..." (means must exists into table ...)
1383 $reg = array();
1384 if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
1385 $field = $reg[1];
1386 $table = $reg[2];
1387 $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
1388
1389 $cachekey = $field.'@'.$table;
1390 if (!empty($filter)) {
1391 $cachekey .= ':'.$filter;
1392 }
1393
1394 // Load content of field@table into cache array
1395 if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
1396 $sql = "SELECT ".$this->db->sanitize($field)." as aliasfield FROM ".$this->db->sanitize($table);
1397 if (!empty($filter)) {
1398 $sql .= forgeSQLFromUniversalSearchCriteria($filter);
1399 }
1400
1401 $resql = $this->db->query($sql);
1402 if ($resql) {
1403 $num = $this->db->num_rows($resql);
1404 $i = 0;
1405 while ($i < $num) {
1406 $obj = $this->db->fetch_object($resql);
1407 if ($obj) {
1408 $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
1409 }
1410 $i++;
1411 }
1412 } else {
1413 dol_print_error($this->db);
1414 }
1415 }
1416
1417 // Now we check cache is not empty (should not) and key is in cache
1418 if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
1419 $tableforerror = $table;
1420 if (!empty($filter)) {
1421 $tableforerror .= ':'.$filter;
1422 }
1423 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
1424 $this->errors[$error]['type'] = 'FOREIGNKEY';
1425 $errorforthistable++;
1426 $error++;
1427 }
1428 } elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
1429 // If test is just a static regex
1430 //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
1431 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
1432 $this->errors[$error]['type'] = 'REGEX';
1433 $errorforthistable++;
1434 $error++;
1435 }
1436 }
1437
1438 // Check HTML injection
1439 $inj = testSqlAndScriptInject($newval, 0);
1440 if ($inj) {
1441 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
1442 $this->errors[$error]['type'] = 'HTMLINJECTION';
1443 $errorforthistable++;
1444 $error++;
1445 }
1446
1447 // Other tests
1448 // ...
1449 }
1450
1451 // Define $listfields and $listvalues to build the SQL request
1452 if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
1453 if (!in_array("socialnetworks", $listfields)) {
1454 $listfields[] = "socialnetworks";
1455 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
1456 $listvalues[$socialkey] = '';
1457 }
1458 //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
1459 if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
1460 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
1461 //var_dump('sk='.$socialkey); // socialkey=19
1462 $socialnetwork = explode("_", $fieldname)[1];
1463 if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
1464 $json = new stdClass();
1465 $json->$socialnetwork = $newval;
1466 $listvalues[$socialkey] = json_encode($json);
1467 } else {
1468 $jsondata = $listvalues[$socialkey];
1469 $json = json_decode($jsondata);
1470 $json->$socialnetwork = $newval;
1471 $listvalues[$socialkey] = json_encode($json);
1472 }
1473 }
1474 } else {
1475 $listfields[] = $fieldname;
1476 // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
1477 if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
1478 $listvalues[] = ($newval == '0' ? (int) $newval : "null");
1479 } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
1480 $listvalues[] = "''";
1481 } else {
1482 $listvalues[] = "'".$this->db->escape($newval)."'";
1483 }
1484 }
1485 }
1486 $i++;
1487 }
1488
1489 // We add hidden fields (but only if there is at least one field to add into table)
1490 // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
1491 // Previously we processed the ->import_fields_array.
1492 if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
1493 // Loop on each hidden fields to add them into listfields/listvalues
1494 foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
1495 if (!preg_match('/^' . preg_quote($alias, '/') . '\./', $tmpkey)) {
1496 continue; // Not a field of current table
1497 }
1498 $keyfieldcache = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $tmpkey);
1499
1500 if (in_array($keyfieldcache, $listfields)) { // avoid duplicates in insert
1501 continue;
1502 } elseif ($tmpval == 'user->id') {
1503 $listfields[] = $keyfieldcache;
1504 $listvalues[] = ((int) $user->id);
1505 } elseif (preg_match('/^lastrowid-/', $tmpval)) {
1506 $tmp = explode('-', $tmpval);
1507 $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
1508 $listfields[] = $keyfieldcache;
1509 $listvalues[] = (int) $lastinsertid;
1510 $keyfield = $keyfieldcache;
1511 //print $tmpkey."-".$tmpval."-".$listfields."-".$listvalues."<br>";exit;
1512 } elseif (preg_match('/^const-/', $tmpval)) {
1513 $tmp = explode('-', $tmpval, 2);
1514 $listfields[] = $keyfieldcache;
1515 $listvalues[] = "'".$this->db->escape($tmp[1])."'";
1516 } elseif (preg_match('/^rule-/', $tmpval)) { // Example: rule-computeAmount, rule-computeDirection, ...
1517 $fieldname = $tmpkey;
1518 if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
1519 if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
1520 $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
1521 $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
1522 $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
1523 $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
1524 $resultload = dol_include_once($file);
1525 if (empty($resultload)) {
1526 dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
1527 break;
1528 }
1529 $classinstance = new $class($this->db);
1530 $computedFieldPos = isset($arrayfield[$fieldname]) ? ((int) $arrayfield[$fieldname]) : 0;
1531 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $computedFieldPos));
1532 if (empty($classinstance->error) && empty($classinstance->errors)) {
1533 $fieldArr = explode('.', $fieldname);
1534 if (count($fieldArr) > 0) {
1535 $fieldname = $fieldArr[1];
1536 }
1537
1538 // Set $listfields and $listvalues
1539 $listfields[] = $fieldname;
1540 if ($type == 'int') {
1541 $listvalues[] = (int) $res;
1542 } elseif ($type == 'double') {
1543 $listvalues[] = (float) $res;
1544 } else {
1545 $listvalues[] = "'".$this->db->escape($res)."'";
1546 }
1547 } else {
1548 $this->errors[$error]['type'] = 'CLASSERROR';
1549 $this->errors[$error]['lib'] = implode(
1550 "\n",
1551 array_merge([$classinstance->error], $classinstance->errors)
1552 );
1553 $errorforthistable++;
1554 $error++;
1555 }
1556 }
1557 }
1558 } else {
1559 $this->errors[$error]['lib'] = 'Bad value of profile setup '.$tmpval.' for array_import_fieldshidden';
1560 $this->errors[$error]['type'] = 'Import profile setup';
1561 $error++;
1562 }
1563 }
1564 }
1565 //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
1566
1567 // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
1568 // so we can try to make the insert or update now.
1569 if (!$errorforthistable) {
1570 //print "$alias/$tablename/$listfields/$listvalues<br>";
1571 if (!empty($listfields)) {
1572 $updatedone = false;
1573 $insertdone = false;
1574 $where = array();
1575
1576 $is_table_category_link = false;
1577 $fname = 'rowid';
1578 if (strpos($tablename, '_categorie_') !== false) {
1579 $is_table_category_link = true;
1580 $fname = '*';
1581 }
1582
1583 if (!empty($updatekeys)) {
1584 // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
1585
1586 if (empty($lastinsertid)) { // No insert done yet for a parent table
1587 $sqlSelect = "SELECT ".$fname." FROM ".$tablename;
1588 $data = array_combine($listfields, $listvalues);
1589 $where = array(); // filters to forge SQL request
1590 $filters = array(); // filters to forge output error message
1591 foreach ($updatekeys as $key) {
1592 $col = $objimport->array_import_updatekeys[0][$key];
1593 $key = preg_replace('/^.*\./i', '', $key);
1594 if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
1595 $tmp = explode("_", $key);
1596 $key = $tmp[0];
1597 $socialnetwork = $tmp[1];
1598 $jsondata = $data[$key];
1599 $json = json_decode($jsondata);
1600 $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
1601 //var_dump($stringtosearch);
1602 //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
1603 $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
1604 $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
1605 //var_dump($where[1]); // This provide a value for sql string inside a like
1606 } else {
1607 $where[] = $key.' = '.$data[$key];
1608 $filters[] = $col.' = '.$data[$key];
1609 }
1610 }
1611 if (!empty($tablewithentity_cache[$tablename])) {
1612 $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1613 $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1614 }
1615 $sqlSelect .= " WHERE ".implode(' AND ', $where);
1616
1617 $resql = $this->db->query($sqlSelect);
1618 if ($resql) {
1619 $num_rows = $this->db->num_rows($resql);
1620 if ($num_rows == 1) {
1621 $res = $this->db->fetch_object($resql);
1622 $lastinsertid = $res->rowid;
1623 $keyfield = 'rowid';
1624 if ($is_table_category_link) {
1625 $lastinsertid = 'linktable';
1626 } // 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
1627 $last_insert_id_array[$tablename] = $lastinsertid;
1628 } elseif ($num_rows > 1) {
1629 $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
1630 $this->errors[$error]['type'] = 'SQL';
1631 $error++;
1632 } else {
1633 // No record found with filters, insert will be tried below
1634 }
1635 } else {
1636 //print 'E';
1637 $this->errors[$error]['lib'] = $this->db->lasterror();
1638 $this->errors[$error]['type'] = 'SQL';
1639 $error++;
1640 }
1641 } else {
1642 // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
1643 // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
1644 // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
1645 // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
1646 // Note: For extrafield tablename, we have in importfieldshidden_array an entry 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
1647 $sqlSelect = "SELECT rowid FROM ".$tablename;
1648 if (empty($keyfield)) {
1649 $keyfield = 'rowid';
1650 }
1651
1652 $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid);
1653
1654 if (!empty($tablewithentity_cache[$tablename])) {
1655 $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1656 }
1657
1658 $resql = $this->db->query($sqlSelect);
1659 if ($resql) {
1660 $res = $this->db->fetch_object($resql);
1661 if ($this->db->num_rows($resql) == 1) {
1662 // We have a row referencing this last foreign key, continue with UPDATE.
1663 } else {
1664 // No record found referencing this last foreign key,
1665 // force $lastinsertid to 0 so we INSERT below.
1666 $lastinsertid = 0;
1667 }
1668 } else {
1669 //print 'E';
1670 $this->errors[$error]['lib'] = $this->db->lasterror();
1671 $this->errors[$error]['type'] = 'SQL';
1672 $error++;
1673 }
1674 }
1675
1676 if (!empty($lastinsertid)) {
1677 // We db escape social network field because he isn't in field creation
1678 if (in_array("socialnetworks", $listfields)) {
1679 $socialkey = array_search("socialnetworks", $listfields);
1680 $tmpsql = $listvalues[$socialkey];
1681 $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1682 }
1683
1684 // Build SQL UPDATE request
1685 $sqlstart = "UPDATE ".$tablename;
1686
1687 $data = array_combine($listfields, $listvalues);
1688 $set = array();
1689 foreach ($data as $key => $val) {
1690 $set[] = $key." = ".$val; // $val was escaped/sanitized previously
1691 }
1692 $sqlstart .= " SET ".implode(', ', $set).", import_key = '".$this->db->escape($importid)."'";
1693 if (empty($keyfield)) {
1694 $keyfield = 'rowid';
1695 }
1696
1697 $sqlend = " WHERE ".$keyfield." = ".((int) $lastinsertid);
1698
1699 if ($is_table_category_link && !empty($where)) {
1700 '@phan-var-force string[] $where';
1701 $sqlend = " WHERE " . implode(' AND ', $where);
1702 }
1703
1704 if (!empty($tablewithentity_cache[$tablename])) {
1705 $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1706 }
1707
1708 $sql = $sqlstart.$sqlend;
1709
1710 // Run update request
1711 $resql = $this->db->query($sql);
1712 if ($resql) {
1713 // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
1714 $updatedone = true;
1715 if (!$importissimulation && $importtriggermode === 'strict_line') {
1716 $restrigger = $this->triggerImportSqlOperation($tablename, 'update', is_numeric($lastinsertid) ? (int) $lastinsertid : 0, $importid, $user, $langs, $conf);
1717 if ($restrigger < 0) {
1718 $this->errors[$error]['lib'] = $langs->trans('ErrorFailedTriggerCall');
1719 $this->errors[$error]['type'] = 'TRIGGER';
1720 $error++;
1721 }
1722 } elseif (!$importissimulation) {
1723 $this->registerImportBulkEvent($tablename, 'update');
1724 }
1725 } else {
1726 //print 'E';
1727 $this->errors[$error]['lib'] = $this->db->lasterror();
1728 $this->errors[$error]['type'] = 'SQL';
1729 $error++;
1730 }
1731 }
1732 }
1733
1734 // Update not done, we do insert
1735 if (!$error && !$updatedone) {
1736 // We db escape social network field because he isn't in field creation
1737 if (in_array("socialnetworks", $listfields)) {
1738 $socialkey = array_search("socialnetworks", $listfields);
1739 $tmpsql = $listvalues[$socialkey];
1740 $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1741 }
1742
1743 // Build SQL INSERT request
1744 $sqlstart = "INSERT INTO ".$tablename."(".implode(", ", $listfields).", import_key";
1745 $sqlend = ") VALUES(".implode(', ', $listvalues).", '".$this->db->escape($importid)."'";
1746 if (!empty($tablewithentity_cache[$tablename])) {
1747 $sqlstart .= ", entity";
1748 $sqlend .= ", ".$conf->entity;
1749 }
1750 if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1751 $sqlstart .= ", ".$objimport->array_import_tables_creator[0][$alias];
1752 $sqlend .= ", ".$user->id;
1753 }
1754 $sql = $sqlstart.$sqlend.")";
1755 //dol_syslog("import_csv.modules", LOG_DEBUG);
1756
1757 // Run insert request
1758 $resql = $this->db->query($sql);
1759 if ($resql) {
1760 if (!$is_table_category_link) {
1761 $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).
1762 }
1763 $insertdone = true;
1764 if (!$importissimulation && $importtriggermode === 'strict_line') {
1765 $triggerrowid = (!$is_table_category_link && !empty($last_insert_id_array[$tablename])) ? (int) $last_insert_id_array[$tablename] : 0;
1766 $restrigger = $this->triggerImportSqlOperation($tablename, 'insert', $triggerrowid, $importid, $user, $langs, $conf);
1767 if ($restrigger < 0) {
1768 $this->errors[$error]['lib'] = $langs->trans('ErrorFailedTriggerCall');
1769 $this->errors[$error]['type'] = 'TRIGGER';
1770 $error++;
1771 }
1772 } elseif (!$importissimulation) {
1773 $this->registerImportBulkEvent($tablename, 'insert');
1774 }
1775 } else {
1776 //print 'E';
1777 $this->errors[$error]['lib'] = $this->db->lasterror();
1778 $this->errors[$error]['type'] = 'SQL';
1779 $error++;
1780 }
1781 }
1782 }
1783 /*else
1784 {
1785 dol_print_error(null,'ErrorFieldListEmptyFor '.$alias."/".$tablename);
1786 }*/
1787 }
1788
1789 if ($error) {
1790 break;
1791 }
1792 }
1793
1794 if ($updatedone) {
1795 $this->nbupdate++;
1796 }
1797 if ($insertdone) {
1798 $this->nbinsert++;
1799 }
1800 }
1801
1802 return 1;
1803 }
1804
1805 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1817 public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
1818 {
1819 // phpcs:enable
1820 return $this->commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, 0);
1821 }
1822
1823 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1830 public function write_header_example($outputlangs)
1831 {
1832 // phpcs:enable
1833 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1834 dol_syslog($msg, LOG_ERR);
1835 $this->errors[] = $msg;
1836 $this->error = $msg;
1837 return '';
1838 }
1839
1840 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1848 public function write_title_example($outputlangs, $headerlinefields)
1849 {
1850 // phpcs:enable
1851 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1852 dol_syslog($msg, LOG_ERR);
1853 $this->errors[] = $msg;
1854 $this->error = $msg;
1855 return '';
1856 }
1857
1858 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1866 public function write_record_example($outputlangs, $contentlinevalues)
1867 {
1868 // phpcs:enable
1869 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1870 dol_syslog($msg, LOG_ERR);
1871 $this->errors[] = $msg;
1872 $this->error = $msg;
1873 return '';
1874 }
1875
1876 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1883 public function write_footer_example($outputlangs)
1884 {
1885 // phpcs:enable
1886 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1887 dol_syslog($msg, LOG_ERR);
1888 $this->errors[] = $msg;
1889 $this->error = $msg;
1890 return '';
1891 }
1892}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage triggers.
Parent class for import file readers.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
getLibVersionForKey($key)
Renvoi version de librairie externe du driver.
getImportTriggerActions($tableElement, $operation, $element, $object=null)
Return trigger actions to execute for an import operation done in SQL legacy mode.
getImportTriggerPrefixFromObject($object)
Return trigger prefix from a business object.
getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object=null)
Resolve import trigger actions from hooks.
getDriverDescForKey($key)
Return description of import drivervoi la description d'un driver import.
getElementFromTableWithPrefix($tableNameWithPrefix)
Get element from table name with prefix.
getDriverLabelForKey($key)
Return label of driver import.
getImportGenericTriggerPrefix($element, $tableElement)
Return generic trigger prefix derived from element or table.
import_get_nb_of_lines($file)
Return nb of records.
getLibLabel()
getDriverLabel
getDriverVersionForKey($key)
Renvoi version d'un driver import.
getDriverLabel()
getDriverLabel
getPictoForKey($key)
Return picto of import driver.
getLibLabelForKey($key)
Renvoi libelle de librairie externe du driver.
buildImportTriggerActionFromPrefix($triggerprefix, $operation)
Build trigger action code from prefix and operation.
getImportTriggerMode()
Return effective trigger mode for import flow.
runImportBulkTrigger($importid, $user, $langs, $conf)
Execute one global trigger for fast_bulk mode.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
import_read_record()
Return array of next record in input file.
import_open_file($file)
Open input file.
import_read_header()
Input header line from file.
getDriverVersion()
getDriverVersion
listOfAvailableImportFormat($db, $maxfilenamelength=0)
Load into memory list of available import format.
commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, $recordpositionbase=0)
Shared implementation of import_insert for CSV/XLSX.
registerImportBulkEvent($tablename, $operation)
Register one SQL operation into bulk trigger stats.
getDriverExtension()
getDriverExtension
getLibVersion()
getLibVersion
write_header_example($outputlangs)
Output header of an example file for this format.
triggerImportSqlOperation($tablename, $operation, $rowid, $importid, $user, $langs, $conf)
Execute triggers for SQL legacy import.
write_footer_example($outputlangs)
Output footer of an example file for this format.
__construct()
Constructor.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
getDriverDesc()
getDriverDesc
import_close_file()
Close file handle.
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition date.lib.php:435
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
const MODULE_MAPPING
This mapping defines the conversion to the current internal names from the alternative allowed names ...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition waf.inc.php:103