action.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. <?php
  2. /** IMPORT / IMPORT **/
  3. //Récuperation d'une liste de import
  4. Action::register('import_search',function(&$response){
  5. global $_;
  6. User::check_access('import','read');
  7. require_once(__DIR__.SLASH.'Import.class.php');
  8. // OPTIONS DE RECHERCHE, A ACTIVER POUR UNE RECHERCHE AVANCEE
  9. $query = 'SELECT main.* FROM '.Import::tableName().' main WHERE 1';
  10. $data = array();
  11. //Recherche simple
  12. if(!empty($_['filters']['keyword'])){
  13. $query .= ' AND main.label LIKE ?';
  14. $data[] = '%'.$_['filters']['keyword'].'%';
  15. }
  16. //Recherche avancée
  17. if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('main.label','main.entity','main.startLine','main.startColumn','main.hasheader','main.file','main.beforeCode','main.afterCode'),$query,$data);
  18. //Tri des colonnes
  19. if(isset($_['sort'])) sort_secure_query($_['sort'],array('main.label','main.entity','main.startLine','main.startColumn','main.hasheader','main.file','main.beforeCode','main.afterCode'),$query,$data);
  20. //Pagination
  21. //Par défaut pour une recherche, 20 items, pour un export 5000 max
  22. $itemPerPage = !empty($_['itemPerPage']) ? $_['itemPerPage'] : 20;
  23. //force le nombre de page max a 50 coté serveur
  24. $itemPerPage = $itemPerPage>50 ? 50 : $itemPerPage;
  25. if($_['export'] == 'true') $itemPerPage = 5000;
  26. $response['pagination'] = Import::paginate($itemPerPage,(!empty($_['page'])?$_['page']:0),$query,$data,'main');
  27. $imports = Import::staticQuery($query,$data,true,0);
  28. $response['rows'] = array();
  29. foreach($imports as $import){
  30. $row = $import->toArray();
  31. $row['entity'] = basename(dirname($row['entity'])).' > '.str_replace('.class.php','',basename($row['entity']));
  32. if($_['export'] == 'true'){
  33. $row['created'] = date('d-m-Y',$row['created']);
  34. $row['updated'] = date('d-m-Y',$row['updated']);
  35. }
  36. $response['rows'][] = $row;
  37. }
  38. /* Mode export */
  39. if($_['export'] == 'true'){
  40. if(empty($response['rows'])) $response['rows'][] = array('Vide'=>'Aucune données');
  41. $fieldsMapping = array();
  42. foreach (Import::fields(false) as $key => $value)
  43. $fieldsMapping[$value['label']] = $key;
  44. $stream = Excel::exportArray($response['rows'],$fieldsMapping ,'Export');
  45. File::downloadStream($stream,'export-import-'.date('d-m-Y').'.xlsx');
  46. exit();
  47. }
  48. });
  49. //Ajout ou modification d'élément import
  50. Action::register('import_save',function(&$response){
  51. global $_,$myUser;
  52. require_once(__DIR__.SLASH.'Import.class.php');
  53. $item = Import::provide();
  54. if($myUser->can('import','configure')){
  55. $oldItem = clone $item;
  56. $item->label = $_['label'];
  57. $item->entity = $_['entity'];
  58. $item->startLine = $_['startLine'];
  59. $item->headerLine = $_['headerLine'];
  60. $item->hasheader = $_['hasheader'];
  61. if(isset($_['meta'])) $item->meta = json_encode($_['meta']);
  62. //verification des droits sur le plugin de l'entitée ciblée
  63. if(!empty($_['entity'])){
  64. $plugin = dirname($item->entity);
  65. $plugin = $plugin == 'class' ? 'core':$plugin;
  66. $plugin = Plugin::parseManifest($plugin.SLASH.'app.json');
  67. if(!$myUser->can($plugin,'edit')) throw new Exception("Vousz n'avez pas la permission d'edition nécessaire sur le module ".$plugin->name." pour sauvegarder cet import");
  68. }
  69. $item->save();
  70. }
  71. if($myUser->can('import','read')){
  72. //Ajout upload Excel
  73. if(!empty($_['file']))
  74. File::save_component('file', 'import/'.$item->id.'/{{label}}');
  75. }
  76. $response = $item->toArray();
  77. });
  78. //Suppression d'élement import
  79. Action::register('import_delete',function(&$response){
  80. global $_;
  81. User::check_access('import','configure');
  82. require_once(__DIR__.SLASH.'Import.class.php');
  83. if(empty($_['id']) || !is_numeric($_['id'])) throw new Exception("Identifiant incorrect");
  84. Import::remove($_['id']);
  85. });
  86. //Import : Gestion upload Excel
  87. Action::register('import_file',function(&$response){
  88. require_once(__DIR__.SLASH.'Import.class.php');
  89. $allowedExtensions = array();
  90. foreach(Import::templates() as $template)
  91. $allowedExtensions[] = $template->extension;
  92. File::handle_component(array(
  93. 'namespace' => 'import', //stockés dans file/import/
  94. 'access' => 'import',
  95. 'extension' => implode(',',$allowedExtensions),
  96. 'limit' => 1,
  97. 'size' => '1000000000', // taille max
  98. 'storage' => 'import/{{data.id}}/*.*' //chemin complet vers le fichier stocké
  99. ),$response);
  100. });
  101. Action::register('import_mapping_deduction',function(&$response){
  102. global $_;
  103. User::check_access('import','read');
  104. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  105. require_once(__ROOT__.SLASH.'plugin/import/Import.class.php');
  106. $import = Import::provide();
  107. $importmappings = ImportMapping::loadAll(array('import'=>$import->id));
  108. require_once($import->entity);
  109. $class = str_replace('.class.php','',basename($import->entity));
  110. $instance = new $class();
  111. $entityFields = $instance->fields(false);
  112. $entityLinks = property_exists($instance,'links') ? $instance->links : array();
  113. $files = glob(File::dir().'import/'.$import->id.'/*.*');
  114. if(count($files)==0) return;
  115. $excel = $files[0];
  116. $template = Import::templates(getExt($excel));
  117. if(!$template) throw new Exception('Cette extension n\'est pas prise en charge par le module import');
  118. $template->meta = json_decode($import->meta,true);
  119. $excel = $template->toArray($excel);
  120. $header = array();
  121. if(count($excel)==0) throw new Exception("L'excel est vide");
  122. //récuperation des en-têtes nominatives (A,B ...)
  123. $columns = array();
  124. $maxColumn = 0;
  125. //calcul du nombre max de colonnes
  126. foreach($excel as $line){
  127. $columnCount = count($line);
  128. $maxColumn = $columnCount>$maxColumn ? $columnCount: $maxColumn;
  129. }
  130. for($i=0;$i<$maxColumn+1;$i++){
  131. $columns[]= array('value'=>import_column_letter($i));
  132. }
  133. //SI un header existe, on récupere les libellés liés aux entete nominatives (ex: A = "Référence")
  134. if($import->hasheader){
  135. $columnsNames = $excel[$import->headerLine-1];
  136. foreach ($columnsNames as $i => $name) {
  137. $columns[$i]['label']= $name['value'];
  138. }
  139. }
  140. $dataColumns = isset($excel[$import->startLine]) ? $excel[$import->startLine] : array();
  141. $response['excelCount'] = count($columns);
  142. $response['entityCount'] = 0;
  143. foreach($columns as $i=>$cell){
  144. //si la cellule est vide, on continue
  145. if($template->emptyCell($cell)) continue;
  146. $importmapping = new ImportMapping();
  147. $importmapping->import = $import->id;
  148. $sample = isset($dataColumns[$i]) ? $dataColumns[$i] : array('value'=>'');
  149. //Déduction du type de valeur en fonction du nom de colonne ou de la valeur
  150. $deductedType = $template->cellType($cell,$sample);
  151. $deductedColumn = array();
  152. //déduction de l'attribut entité en fonction du nom de colonne (si existant)
  153. if(isset($cell['label'])){
  154. $cell['label'] = str_replace('<br>',' ',$cell['label']);
  155. $slugValue = slugify($cell['label']);
  156. foreach($entityFields as $entityField){
  157. $levenshtein = levenshtein(slugify($entityField['label']),$slugValue );
  158. //correspondance parfaite
  159. if($levenshtein == 0){
  160. $deductedColumn = $entityField;
  161. break;
  162. }
  163. //correspondance a 2 lettres près
  164. if( $levenshtein < 2 && strlen($slugValue)> 4 ){
  165. $deductedColumn = $entityField;
  166. break;
  167. }
  168. //si la colonne excel commence par le nom de la colonne courante
  169. if(strpos($slugValue,slugify($entityField['label']))===0){
  170. $deductedColumn = $entityField;
  171. }
  172. }
  173. if(isset($deductedColumn['column'])){
  174. $importmapping->entityField = $deductedColumn['column'];
  175. $deductedType = $deductedColumn['fieldtype'];
  176. if(isset($entityLinks[$importmapping->entityField])){
  177. $subClassFile = __ROOT__.SLASH.$entityLinks[$importmapping->entityField];
  178. //par defaut on lie a l'id de la sous classes
  179. $importmapping->entitySubField = 'id';
  180. //si un attribut label existe sur la sous classe on utilise celui la
  181. if(file_exists($subClassFile)){
  182. require_once($subClassFile);
  183. $subClass = str_replace('.class.php','',basename($subClassFile));
  184. if(property_exists($subClass,'label')) $importmapping->entitySubField = 'label';
  185. }
  186. }
  187. $response['entityCount']++;
  188. }
  189. }
  190. $importmapping->excelColumn = $cell['value'];
  191. if(isset($cell['label'])) $importmapping->excelColumnName = $cell['label'];
  192. $macro = Import::macros($deductedType);
  193. if($macro != false) $importmapping->modifier = $macro['slug'];
  194. $importmapping->save();
  195. }
  196. });
  197. /** IMPORTMAPPING / LINE D\'IMPORT MAPPéE **/
  198. //Récuperation d'une liste de line d\'import mappée
  199. Action::register('import_mapping_search',function(&$response){
  200. global $_;
  201. User::check_access('import','read');
  202. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  203. require_once(__ROOT__.SLASH.'plugin/import/Import.class.php');
  204. $import = Import::provide();
  205. $importmappings = ImportMapping::loadAll(array('import'=>$import->id),array('id'));
  206. require_once($import->entity);
  207. $class = str_replace('.class.php','',basename($import->entity));
  208. $instance = new $class();
  209. $entityFields = $instance->fields(false);
  210. $response['rows'] = array();
  211. $fieldTypes = FieldType::available();
  212. foreach($importmappings as $importmapping){
  213. $row = $importmapping->toArray();
  214. if( isset($entityFields[$row['entityField']]) ){
  215. $field = $entityFields[$row['entityField']];
  216. $row['entityField'] = $field['column'];
  217. $row['entityFieldType'] = isset($fieldTypes[$field['fieldtype']]) ? $fieldTypes[$field['fieldtype']] : '';
  218. }
  219. $response['rows'][] = $row;
  220. }
  221. });
  222. Action::register('import_execute',function(&$response){
  223. global $_,$myUser;
  224. User::check_access('import','read');
  225. require_once(__DIR__.SLASH.'Import.class.php');
  226. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  227. $import = Import::provide();
  228. if(empty($import->id)) throw new Exception('Id import manquant');
  229. //verification des droits sur le plugin de l'entitée ciblée
  230. $plugin = dirname($import->entity);
  231. $plugin = $plugin == 'class' ? 'core':$plugin;
  232. $plugin = Plugin::parseManifest($plugin.SLASH.'app.json');
  233. if(!$myUser->can($plugin->folder,'edit')){
  234. throw new Exception("Vous n'avez pas la permission d'edition nécessaire sur le module ".$plugin->name." ('".$plugin->folder."') pour utiliser cet import");
  235. }
  236. $mapping = array();
  237. $fixedValues = array();
  238. //contient les colonnes qui doivent rester uniques et leurs valeurs
  239. $uniqueColumns = array();
  240. foreach(ImportMapping::loadAll(array('import'=>$import->id)) as $importmapping){
  241. $mapping[$importmapping->excelColumn] = $importmapping;
  242. if(!empty($importmapping->unique)) $uniqueColumns[$importmapping->entityField] = array();
  243. //remplissage d'un tableau des valeurs fixes (non présentes dans l'excel)
  244. if(!empty($importmapping->excelColumnFixedValue) ) $fixedValues[$importmapping->entityField] = $importmapping->excelColumnFixedValue;
  245. }
  246. require_once($import->entity);
  247. $class = str_replace('.class.php','',basename($import->entity));
  248. $instance = new $class();
  249. $entityFields = $instance->fields(false);
  250. $entityLinks = $instance->links;
  251. $files = glob(File::dir().'import/'.$_['id'].'/*.*');
  252. if(count($files)==0) throw new Exception('Excel inexistant');
  253. $excelPath = $files[0];
  254. $response['fileName'] = basename($excelPath);
  255. $template = Import::templates(getExt($excelPath));
  256. if(!$template) throw new Exception('Extension de fichier non prise en charge');
  257. $template->meta = json_decode($import->meta,true);
  258. $excel = $template->toArray($excelPath);
  259. $headers = array();
  260. //récuperation des en-têtes (si non existantes on genere des en-êtes A,B ...)
  261. $response['columns'] = array();
  262. $maxColumn = 0;
  263. //calcul du nombre max de colonnes
  264. foreach($excel as $line){
  265. $columnCount = count($line);
  266. $maxColumn = $columnCount>$maxColumn ? $columnCount: $maxColumn;
  267. }
  268. for($i=0;$i!=$maxColumn;$i++){
  269. $letter = import_column_letter($i);
  270. $headers[]= array('value'=>$letter);
  271. $response['columns'][] = $letter;
  272. }
  273. $entityLabel = $class;
  274. if(property_exists($instance,'entityLabel') && !empty($instance->entityLabel)) $entityLabel = $instance->entityLabel;
  275. $context = array(
  276. 'excel' => $excel,
  277. 'import' => $import,
  278. 'columns' => $response['columns'],
  279. 'plugin' => basename(dirname($import->entity)),
  280. 'entity' => $class,
  281. 'entityLabel' => $entityLabel,
  282. 'headers' => $headers
  283. );
  284. $linkCache = array();
  285. $excelCount = count($excel);
  286. History::put('import',$import->id,'lancement de l\'import ('.$excelCount.' lignes)',History::TYPE_EDIT);
  287. $response['stats'] = array(
  288. 'total' => array('label'=>'Total','slug'=>'total','value'=>$excelCount),
  289. 'imported' => array('label'=>'Importé','slug'=>'imported','value'=>0),
  290. 'error' => array('label'=>'Erreur','slug'=>'error','value'=>0)
  291. );
  292. foreach(ImportMapping::uniqueness() as $slug=>$unique){
  293. if(empty($slug)) continue;
  294. $response['stats'][$slug] = array('label'=>$unique['label'],'slug'=>$slug,'value'=>0);
  295. }
  296. if(!empty($uniqueColumns)){
  297. foreach($class::loadAll() as $item){
  298. foreach($uniqueColumns as $attribute=>$values){
  299. if(!empty($item->$attribute)) $uniqueColumns[$attribute][] = $item->$attribute;
  300. }
  301. }
  302. }
  303. //tableau de cache des classes tierces des relations n-n
  304. $subRelatedCache = array();
  305. foreach($excel as $i => $line){
  306. if($i<$import->startLine -1){
  307. $response['stats']['total']['value']--;
  308. continue;
  309. }
  310. $relatedInstances = array();
  311. $lineNumber = $i+($import->hasheader?2:1) -1;
  312. $context['lineNumber'] = $lineNumber;
  313. $context['i'] = $i;
  314. $context['line'] = $line;
  315. $instance = new $class();
  316. if($template->emptyLine($line)){
  317. $response['stats']['total']['value']--;
  318. continue;
  319. }
  320. foreach($line as $u=>$cell){
  321. $columnName = isset($headers[$u])? $headers[$u]['value'] : $u;
  322. $context['columnNumber'] = $u;
  323. $context['columnName'] = $columnName;
  324. try{
  325. if($template->emptyCell($cell)) continue;
  326. if(!isset($mapping[$columnName])) continue;
  327. $importmapping = $mapping[$columnName];
  328. if(empty($importmapping->entityField))continue;
  329. $entityField = isset($entityFields[$importmapping->entityField]) ? $entityFields[$importmapping->entityField] : null;
  330. $context['entityField'] = $entityField;
  331. if(!empty($importmapping->modifier)){
  332. $macro = Import::macros($importmapping->modifier);
  333. $mutator = $macro['mutator'];
  334. $cell['value'] = $mutator($cell['value'],$context);
  335. }
  336. $attribute = $importmapping->entityField;
  337. //Si le champ est lié a une autre entité en n-1 (un champs de l'entité courante point vers l'id d'une autre entité)
  338. if(isset($entityLinks[$importmapping->entityField]) && basename($entityLinks[$importmapping->entityField])!='Dictionary.class.php'){
  339. $file = $entityLinks[$importmapping->entityField];
  340. require_once(__ROOT__.SLASH.$file);
  341. $subClass = str_replace('.class.php','',basename($file));
  342. if(!isset($linkCache[$file])) $linkCache[$file] = array();
  343. if(!isset($linkCache[$file][$cell['value']])){
  344. //on recherche l'entrée ciblé en base ayant le libellé de la valeur excel
  345. $subInstance = $subClass::load(array($importmapping->entitySubField=>$cell['value']));
  346. if(is_object($subInstance) && $subInstance->id!=0) $linkCache[$file][$cell['value']] = $subInstance->id;
  347. }
  348. //on remplace la valeur par l'id de l'objet trouvé
  349. if( isset($linkCache[$file][$cell['value']]) && is_numeric($linkCache[$file][$cell['value']])) $cell['value'] = $linkCache[$file][$cell['value']];
  350. }
  351. //Si le champ est lié a une autre entité
  352. if(!empty($importmapping->entityRelatedField)){
  353. //On récupere le chemin de la classe de l'autre entité
  354. $relatedFile = $importmapping->entityRelated;
  355. //on vérifie que le fichier de classe existe
  356. if(file_exists($relatedFile)){
  357. //on inclus le fichier de classe
  358. require_once($relatedFile);
  359. //on récupere le nom de la classe
  360. $relatedClass = str_replace('.class.php','',basename($relatedFile));
  361. //on l'instancie
  362. $relatedManager = new $relatedClass();
  363. //on récupere les champs de la classe en questions
  364. $relatedManagerFields = $relatedManager->fields(false);
  365. //Pour chaques champs
  366. foreach($relatedManagerFields as $relatedInstanceField){
  367. //Si une classe tierce est liée (attribut 'link') est qu'elle a le même nom que la classe
  368. //principale qui est importée on la stock en tant que colonne de relation
  369. if(isset($relatedInstanceField['link']) && basename($relatedInstanceField['link']) == basename($import->entity) ){
  370. $relationColumn = $relatedInstanceField['column'];
  371. }
  372. }
  373. $attribute = $importmapping->entityRelatedField;
  374. $attributePath = explode('.',$attribute);
  375. //si le champ est en relation 1-n (une autre entité point vers l'id de l'entitée courante)
  376. if(count($attributePath)==1){
  377. $relatedInstance = isset($relatedInstances[$relationColumn]) ? $relatedInstances[$relationColumn] : array('instance'=> new $relatedClass(),'childs'=>array());
  378. $relatedInstance['instance']->$attribute = $cell['value'];
  379. if(isset($relationColumn)) $relatedInstances[$relationColumn] = $relatedInstance;
  380. continue;
  381. }else if(count($attributePath)>1){
  382. //relations n-n (une autre entité pointe vers l'id de l'entitée courante elle même pointée par une troisieme entitée)
  383. // pour le moment ne gère pas en recursive, un seul niveau de n-n pris en charge
  384. /*
  385. $relatedInstance = isset($relatedInstances['tender']) ? $relatedInstances['tender'] : array('instance'=> new Assigment(),'childs'=>array());
  386. */
  387. $relatedInstance = isset($relatedInstances[$relationColumn]) ? $relatedInstances[$relationColumn] : array('instance'=> new $relatedClass(),'childs'=>array());
  388. //$relatedManagerField = $relatedManagerFields['assignee'];
  389. $relatedManagerField = $relatedManagerFields[$attributePath[0]];
  390. //requie_once(__ROOT__.SLASH.'/plugin/publictender/Assignee.class.php')
  391. require_once(__ROOT__.SLASH.$relatedManagerField['link']);
  392. //$childClass = Assignee;
  393. $childClass = str_replace('.class.php','',basename($relatedManagerField['link']));
  394. if(isset($relatedInstance['childs'][$attributePath[0]]['instance'])){
  395. $childInstance = $relatedInstance['childs'][$attributePath[0]]['instance'];
  396. }else{
  397. $childInstance = new $childClass();
  398. }
  399. $property = $attributePath[1];
  400. $childInstance->$property = $cell['value'];
  401. $relatedInstance['childs'][$attributePath[0]] = array('instance'=>$childInstance);
  402. if(isset($relationColumn)) $relatedInstances[$relationColumn] = $relatedInstance;
  403. continue;
  404. }else{
  405. continue;
  406. }
  407. }
  408. }
  409. //Vérification de l'unicité si activée
  410. if(!empty($importmapping->unique)){
  411. $uniqueExistingValues = $uniqueColumns[$importmapping->entityField];
  412. //Si la valeur existe déja
  413. if(in_array($cell['value'],$uniqueExistingValues)){
  414. switch($importmapping->unique){
  415. //si on a configuré le skip, on ignore la nouvelle ligne importée
  416. case ImportMapping::UNIQUE_SKIP:
  417. import_report_line($response,$context,ImportMapping::UNIQUE_SKIP,'Ignoré','Ligne non unique, ligne d\'import ignorée');
  418. $response['stats'][ImportMapping::UNIQUE_SKIP]['value']++;
  419. //on utilise 3 car le switch est lui même considéré comme une boucle par php
  420. continue 3;
  421. break;
  422. //si on a configuré le erase, on supprime la ligne existante en base
  423. case ImportMapping::UNIQUE_ERASE:
  424. $class::delete(array($importmapping->entityField => $cell['value']));
  425. import_report_line($response,$context,ImportMapping::UNIQUE_ERASE,'Écrasé','Ligne non unique, correspondance en base ecrasée');
  426. $response['stats'][ImportMapping::UNIQUE_ERASE]['value']++;
  427. break;
  428. }
  429. }
  430. //on ajoute la nouvelle valeur unique dans le tableau de gestion des unicités
  431. $uniqueColumns[$importmapping->entityField][] = $cell['value'];
  432. }
  433. $instance->$attribute = $cell['value'];
  434. }catch(Exception $e){
  435. import_report_line($response,$context,'error','Erreur',$e->getMessage().' L'.$e->getLine());
  436. $response['stats']['error']['value']++;
  437. History::put('import',$import->id,'L'.$lineNumber.' colonne '.($context['columnNumber']+1).' : '.$e->getMessage().' ('.$e->getLine().')','error');
  438. continue;
  439. }
  440. }
  441. //remplissage des valeurs fixes pour l'objet
  442. foreach($fixedValues as $enfityField=>$value){
  443. $instance->$enfityField = $value;
  444. }
  445. $response['stats']['imported']['value']++;
  446. $instance->save();
  447. foreach($relatedInstances as $property=>$relatedInstance){
  448. //n-n
  449. if(!empty($relatedInstance['childs'])){
  450. foreach($relatedInstance['childs'] as $subProperty => $subRelatedInstance){
  451. //On verifie si l'entité tierce est existante en base
  452. $filters = array();
  453. $subRelatedClass = get_class($subRelatedInstance['instance']);
  454. foreach($subRelatedInstance['instance']->fields() as $field){
  455. if(in_array($field,array('created','id','updated','updater','creator'))) continue;
  456. $filters[$field] = $subRelatedInstance['instance']->$field;
  457. }
  458. $filterChain = sha1(json_encode($filters));
  459. if(isset($subRelatedCache[$filterChain])){
  460. $existing = $subRelatedCache[$filterChain];
  461. }else{
  462. $existing = $subRelatedClass::load($filters);
  463. if($existing != false) $subRelatedCache[$filterChain] = $existing;
  464. }
  465. //si l'entité tierce n'est pas existante, on la créé
  466. if(!$existing){
  467. $subRelatedInstance['instance']->save();
  468. //si l'entité tierce existe, on la prend comme référence
  469. }else{
  470. $subRelatedInstance['instance'] = $existing;
  471. }
  472. $subRelatedCache[$filterChain] = $subRelatedInstance['instance'];
  473. $relatedInstance['instance']->$subProperty = $subRelatedInstance['instance']->id;
  474. $relatedInstance['instance']->$property = $instance->id;
  475. $relatedInstance['instance']->save();
  476. }
  477. //1-n
  478. }else{
  479. $relatedInstance['instance']->$property = $instance->id;
  480. $relatedInstance['instance']->save();
  481. }
  482. }
  483. }
  484. if(file_exists($excelPath)) unlink($excelPath);
  485. History::put('import',$import->id,'Fin de l\'import, '.$response['stats']['imported']['value'].'/'.$response['stats']['total']['value'].' importés',History::TYPE_EDIT);
  486. });
  487. //Ajout ou modification d'élément line d\'import mappée
  488. Action::register('import_template_setting',function(&$response){
  489. global $_;
  490. User::check_access('import','configure');
  491. require_once(__DIR__.SLASH.'Import.class.php');
  492. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  493. $import = Import::provide('import');
  494. $files = glob(File::dir().'import/'.$import->id.'/*.*');
  495. if(count($files)==0) return $response['form'] = '';
  496. $excel = $files[0];
  497. $template = Import::templates(getExt($excel));
  498. $meta = json_decode($import->meta,true);
  499. $template->meta = $meta;
  500. $excel = $template->toArray($excel);
  501. $response['headers'] = array();
  502. $maxColumn = 0;
  503. //calcul du nombre max de colonnes
  504. foreach($excel as $line){
  505. $columnCount = count($line);
  506. $maxColumn = $columnCount>$maxColumn ? $columnCount: $maxColumn;
  507. }
  508. for($i=0;$i!=$maxColumn;$i++){
  509. $letter = import_column_letter($i);
  510. $response['headers'][$letter]= array('value'=>$letter);
  511. }
  512. $response['form'] = '';
  513. foreach($template->settings() as $slug=>$field){
  514. $field['id'] = $slug;
  515. if(isset($meta[$field['id']])) $field['value'] = $meta[$field['id']];
  516. $field['attributes']['onchange'] = '"import_save()"';
  517. $field = FieldType::toHtml($field,null,array('allowCustomLabel'=>true));
  518. $response['form'] .= $field['label'].' '.(!empty($field['legend'])?'<small class="text-muted">'.$field['legend'].'</small>':'').' '.$field['input'];
  519. }
  520. });
  521. //Ajout ou modification d'élément line d\'import mappée
  522. Action::register('import_mapping_save',function(&$response){
  523. global $_;
  524. User::check_access('import','configure');
  525. require_once(__DIR__.SLASH.'Import.class.php');
  526. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  527. $item = ImportMapping::provide();
  528. $item->excelColumn = isset($_['excelColumn']) ? $_['excelColumn'] : 'Sans titre';
  529. $item->excelColumnFixedValue = isset($_['excelColumnFixedValue']) ? $_['excelColumnFixedValue'] : '';
  530. $item->modifier = isset($_['modifier']) ? $_['modifier']: '';
  531. $item->entityField = isset($_['entityField']) ? $_['entityField']: '';
  532. $item->entitySubField = isset($_['entitySubField']) ? $_['entitySubField']: '';
  533. $item->entityRelated = isset($_['entityRelated']) ? $_['entityRelated']: '';
  534. $item->entityRelatedField = isset($_['entityRelatedField']) ? $_['entityRelatedField']: '';
  535. $item->unique = isset($_['unique']) ? $_['unique']: '';
  536. $item->import = $_['import'];
  537. $item->save();
  538. $response = $item->toArray();
  539. });
  540. //Récuperation ou edition d'élément line d\'import mappée
  541. Action::register('import_mapping_edit',function(&$response){
  542. global $_;
  543. User::check_access('import','configure');
  544. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  545. $response = ImportMapping::getById($_['id'])->toArray();
  546. if(!isset($response['modifier'])) $response['modifier'] = '';
  547. });
  548. //Suppression d'élement line d\'import mappée
  549. Action::register('import_mapping_delete',function(&$response){
  550. global $_;
  551. User::check_access('import','configure');
  552. require_once(__DIR__.SLASH.'ImportMapping.class.php');
  553. if(empty($_['id'])) throw new Exception("Identifiant incorrect");
  554. if($_['id'] == 'all'){
  555. ImportMapping::delete(array('import'=>$_['import']));
  556. }else{
  557. ImportMapping::deleteById($_['id']);
  558. }
  559. });
  560. /* COMPOSANT*/
  561. //recherche autocomplete
  562. Action::register('import_autocomplete',function(&$response){
  563. global $myUser,$_;
  564. require_once(__DIR__.SLASH.'Import.class.php');
  565. if (!$myUser->connected()) throw new Exception("Vous devez être connecté", 401);
  566. $response['rows'] = array();
  567. $data = array("%".$_['keyword']."%");
  568. //retourne en priorité les matchs à 100%, pour les match keyword%, puis les autres
  569. $query = 'SELECT c.* FROM '.Import::tableName().' c WHERE (c.label LIKE ?) ';
  570. $query .= ' LIMIT 10';
  571. $devices = Import::staticQuery($query,$data,true);
  572. foreach($devices as $item){
  573. $response['rows'][] = array(
  574. 'label'=>html_entity_decode($item->label, ENT_QUOTES),
  575. 'id'=>$item->id,
  576. );
  577. }
  578. });
  579. //Récuperation valeur composant depuis l'uid
  580. Action::register('import_by_uid',function(&$response){
  581. global $myUser,$_;
  582. if (!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  583. require_once(__DIR__.SLASH.'Import.class.php');
  584. $response['items'] = array();
  585. $query = 'SELECT main.* FROM '.Import::tableName().' main WHERE main.id IN(';
  586. $query .= implode(',', array_fill(0, count($_['items']), '?'));
  587. $query .= ')';
  588. foreach(Import::staticQuery($query,$_['items'],true) as $item) {
  589. $row = $item->toArray();
  590. $row['label'] = html_entity_decode($row['label'], ENT_QUOTES);
  591. $response['items'][$row['id']] = $row;
  592. }
  593. });
  594. //Sauvegarde des configurations de Import
  595. Action::register('import_setting_save',function(&$response){
  596. global $_,$conf;
  597. User::check_access('import','configure');
  598. //Si input file "multiple", possibilité de normaliser le
  599. //tableau $_FILES récupéré avec la fonction => normalize_php_files();
  600. foreach(Configuration::setting('import') as $key=>$value){
  601. if(!is_array($value)) continue;
  602. $allowed[] = $key;
  603. }
  604. foreach ($_['fields'] as $key => $value) {
  605. if(in_array($key, $allowed))
  606. $conf->put($key,$value);
  607. }
  608. });
  609. ?>