Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
externallocationmap.php
1<?
3
13
20{
21 //Dlivery idtifyer, stored in \Bitrix\Sale\Location\ExternalServiceTable : CODE
23 //Path to file (if exist) were we can get prepared locations map
24 const CSV_FILE_PATH = '';
25 const CITY_NAME_IDX = 0;
26 const REGION_NAME_IDX = 1;
27 const CITY_XML_ID_IDX = 2;
28
35 protected static function getAllLocations()
36 {
37 throw new SystemException('Must be impemented!');
38 }
39
45 public static function getInternalId($externalCode)
46 {
47 if($externalCode == '')
48 return 0;
49
50 $srvId = static::getExternalServiceId();
51
52 if($srvId <= 0)
53 return 0;
54
55 $res = ExternalTable::getList(array(
56 'filter' => array(
57 '=XML_ID' => $externalCode,
58 '=SERVICE_ID' => $srvId
59 )
60 ));
61
62 if($loc = $res->fetch())
63 return $loc['ID'];
64
65 return 0;
66 }
67
73 public static function getExternalId($locationId)
74 {
75 if($locationId == '')
76 return '';
77
78 $srvId = static::getExternalServiceId();
79
80 if($srvId <= 0)
81 return 0;
82
83 $res = LocationTable::getList(array(
84 'filter' => array(
85 array(
86 'LOGIC' => 'OR',
87 '=CODE' => $locationId,
88 '=ID' => $locationId
89 ),
90 '=EXTERNAL.SERVICE_ID' => $srvId
91 ),
92 'select' => array(
93 'ID', 'CODE',
94 'XML_ID' => 'EXTERNAL.XML_ID'
95 )
96 ));
97
98 $result = '';
99
100 if($loc = $res->fetch())
101 $result = $loc['XML_ID'];
102
103 if($result == '')
104 $result = self::getUpperCityExternalId($locationId, $srvId);
105
106 return $result;
107 }
108
109 protected static function getUpperCityExternalId($locationId, $srvId)
110 {
111 $result = '';
112
113 $res = LocationTable::getList(array(
114 'filter' => array(
115 array(
116 'LOGIC' => 'OR',
117 '=CODE' => $locationId,
118 '=ID' => $locationId
119 ),
120 ),
121 'select' => array(
122 'ID', 'CODE', 'LEFT_MARGIN', 'RIGHT_MARGIN',
123 'TYPE_CODE' => 'TYPE.CODE'
124 )
125 ));
126
127 if(!$loc = $res->fetch())
128 return '';
129
130 if($loc['TYPE_CODE'] == 'CITY')
131 return '';
132
133 $res = LocationTable::getList(array(
134 'filter' => array(
135 '<LEFT_MARGIN' => $loc['LEFT_MARGIN'],
136 '>RIGHT_MARGIN' => $loc['RIGHT_MARGIN'],
137 'TYPE.CODE' => 'CITY',
138 '=EXTERNAL.SERVICE_ID' => $srvId
139 ),
140 'select' => array(
141 'ID', 'CODE', 'LEFT_MARGIN', 'RIGHT_MARGIN',
142 'XML_ID' => 'EXTERNAL.XML_ID'
143 )
144 ));
145
146 if($locParent = $res->fetch())
147 return $locParent['XML_ID'];
148
149 return $result;
150 }
151
157 public static function getCityId($locationId)
158 {
159 if($locationId == '')
160 return 0;
161
162 $res = LocationTable::getList(array(
163 'filter' => array(
164 array(
165 'LOGIC' => 'OR',
166 '=CODE' => $locationId,
167 '=ID' => $locationId,
168 ),
169 array(
170 '=TYPE.CODE' => 'CITY',
171 '=PARENTS.TYPE.CODE' => 'CITY'
172 ),
173 ),
174 'select' => array(
175 'ID', 'CODE',
176 'TYPE_CODE' => 'TYPE.CODE',
177 'PID' => 'PARENTS.ID',
178 )
179 ));
180
181 if($loc = $res->fetch())
182 {
183 return $loc['PID'];
184 }
185
186 return 0;
187 }
188
189
194 public static function install()
195 {
196 $result = new Result();
197
198 if(static::isInstalled())
199 return $result;
200
201 $imported = static::importFromCsv($_SERVER['DOCUMENT_ROOT'].static::CSV_FILE_PATH);
202
203 if(intval($imported) <= 0)
204 $result = static::refresh();
205
206 return $result;
207 }
208
214 public static function unInstall()
215 {
216 $result = new Result();
217
218 if(!static::isInstalled())
219 return $result;
220
221 $con = \Bitrix\Main\Application::getConnection();
222 $sqlHelper = $con->getSqlHelper();
223 $srvId = $sqlHelper->forSql(static::getExternalServiceId());
224 $con->queryExecute("DELETE FROM b_sale_loc_ext WHERE SERVICE_ID=".$srvId);
225 ExternalServiceTable::delete($srvId);
226 return $result;
227 }
228
233 public static function isInstalled()
234 {
235 static $result = null;
236
237 if($result === null)
238 {
239 $result = false;
240 $res = ExternalServiceTable::getList(array(
241 'filter' => array(
242 '=CODE' => static::EXTERNAL_SERVICE_CODE,
243 '!=EXTERNAL.ID' => false
244 )
245 ));
246
247 if($res->fetch())
248 $result = true;
249 }
250
251 return $result;
252 }
253
259 public static function refresh()
260 {
261 set_time_limit(0);
262 $result = new Result();
263 $res = static::getAllLocations();
264
265 if($res->isSuccess())
266 {
267 $locations = $res->getData();
268
269 if(is_array($locations) && !empty($locations))
270 {
271 $res = static::setMap($locations);
272
273 if(!$res->isSuccess())
274 $result->addErrors($res->getErrors());
275 }
276 }
277 else
278 {
279 $result->addErrors($res->getErrors());
280 }
281
282 return new Result();
283 }
284
292 public static function importFromCsv($path)
293 {
294 set_time_limit(0);
295
296 if($path == '')
297 return 0;
298
299 if(!\Bitrix\Main\IO\File::isFileExists($path))
300 return 0;
301
302 $content = \Bitrix\Main\IO\File::getFileContents($path);
303
304 if($content === false)
305 return 0;
306
308
309 if(intval($srvId) < 0)
310 return 0;
311
312 $lines = explode("\n", $content);
313
314 if(!is_array($lines))
315 return array();
316
317 $result = 0;
318
319 foreach($lines as $line)
320 {
321 $columns = explode(';', $line);
322
323 if(!is_array($columns) || count($columns) != 2)
324 continue;
325
326 $res = LocationTable::getList(array(
327 'filter' => array(
328 '=CODE' => $columns[0],
329 ),
330 'select' => array('ID')
331 ));
332
333 if($loc = $res->fetch())
334 if(self::setExternalLocation($srvId, $loc['ID'], $columns[1]))
335 $result++;
336 }
337
338 return $result;
339 }
340
346 public static function exportToCsv($path)
347 {
348 set_time_limit(0);
349 $srvId = static::getExternalServiceId();
350
351 if($srvId <= 0)
352 return false;
353
354 $res = LocationTable::getList(array(
355 'filter' => array(
356 '=EXTERNAL.SERVICE_ID' => $srvId
357 ),
358 'select' => array(
359 'CODE',
360 'XML_ID' => 'EXTERNAL.XML_ID'
361 )
362 ));
363
364 $content = '';
365
366 while($row = $res->fetch())
367 if($row['CODE'] <> '')
368 $content .= $row['CODE'].";".$row['XML_ID']."\n";
369
370 return \Bitrix\Main\IO\File::putFileContents($path, $content);
371 }
372
378 public static function getExternalServiceId()
379 {
380 if(static::EXTERNAL_SERVICE_CODE == '')
381 throw new SystemException('EXTERNAL_SERVICE_CODE must be defined!');
382
383 static $result = null;
384
385 if($result !== null)
386 return $result;
387
388 $res = ExternalServiceTable::getList(array(
389 'filter' => array('=CODE' => static::EXTERNAL_SERVICE_CODE)
390 ));
391
392 if($srv = $res->fetch())
393 {
394 $result = $srv['ID'];
395 return $result;
396 }
397
398 $res = ExternalServiceTable::add(array('CODE' => static::EXTERNAL_SERVICE_CODE));
399
400 if(!$res->isSuccess())
401 {
402 $result = 0;
403 return $result;
404 }
405
406 $result = $res->getId();
407 return $result;
408 }
409
415 protected static function utfDecode($str)
416 {
417 if(mb_strtolower(SITE_CHARSET) != 'utf-8')
418 $str = Encoding::convertEncoding($str, 'UTF-8', SITE_CHARSET);
419
420 return $str;
421 }
422
431 protected static function setMap(array $cities)
432 {
433 $result = new Result();
434
435 if(empty($cities))
436 throw new ArgumentNullException('cities');
437
438 $xmlIdExist = array();
439 $locationIdExist = array();
440 $xmlIds = array_keys($cities);
441 $srvId = static::getExternalServiceId();
442
443 $res = ExternalTable::getList(array(
444 'filter' => array(
445 '=SERVICE_ID' => $srvId
446 )
447 ));
448
449 while($map = $res->fetch())
450 {
451 $xmlIdExist[] = $map['XML_ID'];
452 $locationIdExist[] = $map['LOCATION_ID'];
453
454 //we already have this location
455 if(in_array($map['XML_ID'], $xmlIds))
456 unset($cities[$map['XML_ID']]);
457 }
458
459 //nothing to import
460 if(empty($cities))
461 return $result;
462
463 foreach($cities as $city)
464 {
465 $xmlId = $city[self::CITY_XML_ID_IDX];
466 $locId = static::getLocationIdByNames($city[static::CITY_NAME_IDX], '', '', $city[static::REGION_NAME_IDX]);
467
468 if(intval($locId) > 0 && !in_array($xmlId, $xmlIdExist) && !in_array($locId, $locationIdExist))
469 {
470 ExternalTable::add(array(
471 'SERVICE_ID' => $srvId,
472 'LOCATION_ID' => $locId,
473 'XML_ID' => $xmlId
474 ));
475
476 $xmlIdExist[] = $xmlId;
477 $locationIdExist[] = $locId;
478 }
479
480 unset($cities[$xmlId]);
481 }
482
483 return $result;
484 }
485
496 public static function setExternalLocation2($srvId, $locationId, $xmlId, $updateExist = false)
497 {
498 if($xmlId == '')
499 throw new ArgumentNullException('code');
500
501 if($srvId == '')
502 throw new ArgumentNullException('srvId');
503
504 if(intval($locationId) <= 0)
505 throw new ArgumentNullException('locationId');
506
507 static $locCache = array();
508
509 if(!isset($locCache[$srvId]))
510 {
511 $locCache[$srvId] = array();
512
513 $eRes = ExternalTable::getList(array(
514 'filter' => array(
515 '=SERVICE_ID' => $srvId,
516 ),
517 'select' => array('ID', 'SERVICE_ID', 'LOCATION_ID', 'XML_ID')
518 ));
519
520 while($loc = $eRes->fetch())
521 $locCache[$srvId][$loc['LOCATION_ID'].'##'.$loc['XML_ID']] = $loc['ID'];
522 }
523
524 if(!empty($locCache[$srvId][$locationId.'##'.$xmlId]))
525 {
526 if($updateExist)
527 {
528 $res = ExternalTable::update(
529 $locCache[$srvId][$locationId.'##'.$xmlId],
530 array(
531 'SERVICE_ID' => $srvId,
532 'XML_ID' => $xmlId,
533 'LOCATION_ID' => $locationId
534 ));
535
536 return $res;
537 }
538 else
539 {
540 $result = new \Bitrix\Main\Entity\UpdateResult();
541 $result->addError(new Error('External location already exists', 'EXTERNAL_LOCATION_EXISTS'));
542 return $result;
543 }
544 }
545 else
546 {
547 $res = ExternalTable::add(array(
548 'SERVICE_ID' => $srvId,
549 'XML_ID' => $xmlId,
550 'LOCATION_ID' => $locationId
551 ));
552
553 $locCache[$srvId][$locationId.'##'.$xmlId] = $res->getId();
554 return $res;
555 }
556 }
557
568 public static function setExternalLocation($srvId, $locationId, $xmlId, $updateExist = false)
569 {
570 $result = self::setExternalLocation2($srvId, $locationId, $xmlId, $updateExist);
571 return $result->isSuccess();
572 }
573
574 protected static function isNormalizedTableFilled()
575 {
576 $count = 0;
577 $con = \Bitrix\Main\Application::getConnection();
578 $res = $con->query("SELECT COUNT(1) AS COUNT FROM b_sale_hdaln");
579
580 if($row = $res->fetch())
581 $count = intval($row['COUNT']);
582
583 return $count > 0;
584 }
585
593 public static function fillNormalizedTable($startId = false, $timeout = 0)
594 {
595 set_time_limit(0);
596 $startTime = mktime(true);
597 $lastProcessedId = 0;
598 $con = \Bitrix\Main\Application::getConnection();
599 $sqlHelper = $con->getSqlHelper();
600
601 if(intval($startId) <= 0)
602 $con->queryExecute("DELETE FROM b_sale_hdaln");
603
604 $query = "SELECT
605 L.ID,
606 L.LEFT_MARGIN,
607 L.RIGHT_MARGIN,
608 N.NAME_UPPER
609 FROM
610 b_sale_location AS L
611 INNER JOIN b_sale_loc_name AS N ON L.ID = N.LOCATION_ID
612 INNER JOIN b_sale_loc_type AS T ON L.TYPE_ID = T.ID
613 WHERE
614 N.LANGUAGE_ID = 'ru'
615 AND (T.CODE = 'VILLAGE' OR T.CODE = 'CITY')";
616
617 if($startId !== false)
618 $query .= " AND L.ID > ".strval(intval($startId));
619
620 $query .= " ORDER BY ID ASC";
621 $res = $con->query($query);
622
623 while($loc = $res->fetch())
624 {
625 $con->queryExecute("
626 INSERT INTO
627 b_sale_hdaln (LOCATION_ID, LEFT_MARGIN, RIGHT_MARGIN, NAME)
628 VALUES(
629 ".intval($loc['ID']).",
630 ".intval($loc['LEFT_MARGIN']).",
631 ".intval($loc['RIGHT_MARGIN']).",
632 '".$sqlHelper->forSql(
633 preg_replace(
634 '/\s*(\‍(.*\‍))/i'.BX_UTF_PCRE_MODIFIER,
635 '',
636 \Bitrix\Sale\Location\Comparator::flatten($loc['NAME_UPPER']))
637 )."'
638 )
639 ");
640
641 $lastProcessedId = $loc['ID'];
642
643 if($timeout > 0 && (mktime(true)-$startTime) >= $timeout)
644 break;
645 }
646
647 return $lastProcessedId;
648 }
649
661 public static function getLocationIdByNames($name, $city, $subregion, $region, $country = '', $exactOnly = false)
662 {
663 $nameNorm = Comparator::normalizeEntity($name, 'LOCALITY');
664 $subregionNorm = null;
665 $regionNorm = null;
666 $cityNorm = null;
667 $searchNames = array($name);
668
669 if(!$exactOnly)
670 $searchNames = array_merge($searchNames, \Bitrix\Sale\Location\Comparator::getLocalityNamesArray($nameNorm['NAME'], $nameNorm['TYPE']));
671
672 $searchNames = array_map(array('\Bitrix\Sale\Location\Comparator', 'flatten'), $searchNames);
673 $searchNames = array_map(function($name){return "'".$name."'";}, $searchNames);
674
675 if(empty($searchNames))
676 return 0;
677
678 $con = \Bitrix\Main\Application::getConnection();
679 $sqlHelper = $con->getSqlHelper();
680 $margins = array();
681 $res = $con->query("
682 SELECT
683 N.LOCATION_ID AS LOCATION_ID,
684 N.LEFT_MARGIN AS LEFT_MARGIN,
685 N.RIGHT_MARGIN AS RIGHT_MARGIN,
686 N.NAME AS NAME
687 FROM
688 b_sale_hdaln AS N
689 LEFT JOIN b_sale_loc_ext AS E
690 ON N.LOCATION_ID = E.LOCATION_ID AND E.SERVICE_ID = ".$sqlHelper->forSql(self::getExternalServiceId())."
691 WHERE
692 E.LOCATION_ID IS NULL
693 AND NAME IN (".implode(', ', $searchNames).")");
694
695 $results = array();
696 $exact = array();
697
698 while($loc = $res->fetch())
699 {
700 if(Comparator::isEntityEqual($loc['NAME'], $nameNorm, 'LOCALITY'))
701 {
702 $margins[] = array($loc['LOCATION_ID'], $loc['LEFT_MARGIN'], $loc['RIGHT_MARGIN'], $loc['NAME']);
703 $results[$loc['LOCATION_ID']] = array('NAME' => true);
704
705 if($loc['NAME'] == $nameNorm["NAME"])
706 $exact[] = $loc['LOCATION_ID'];
707 }
708 }
709
710 if(empty($margins))
711 return 0;
712
713 $marginFilter = array('LOGIC' => 'OR');
714
715 foreach($margins as $v)
716 $marginFilter[] = array('<LEFT_MARGIN' => $v[1], '>RIGHT_MARGIN' => $v[2]);
717
718 $res = LocationTable::getList(array(
719 'filter' => array(
720 '=NAME.LANGUAGE_ID' => LANGUAGE_ID,
721 '=TYPE.CODE' => array('SUBREGION', 'REGION', 'CITY'),
722 $marginFilter
723 ),
724 'select' => array(
725 'ID',
726 'PARENTS_NAME_UPPER' => 'NAME.NAME_UPPER',
727 'PARENTS_TYPE_CODE' => 'TYPE.CODE',
728 'LEFT_MARGIN', 'RIGHT_MARGIN'
729 )
730 ));
731
732 while($loc = $res->fetch())
733 {
734 $ids = self::getIdByMargin($loc['LEFT_MARGIN'], $loc['RIGHT_MARGIN'], $margins);
735
736 foreach($ids as $id)
737 {
738 if(in_array(false, $results[$id], true))
739 continue;
740
741 $found = null;
742
743 if($loc['PARENTS_TYPE_CODE'] == 'REGION' && $region <> '')
744 {
745 if(!is_array($regionNorm))
746 $regionNorm = Comparator::normalizeEntity($region, 'REGION');
747
748 $found = Comparator::isEntityEqual($loc['PARENTS_NAME_UPPER'], $regionNorm, 'REGION');
749 }
750 elseif($subregion <> '' && $loc['PARENTS_TYPE_CODE'] == 'SUBREGION')
751 {
752 if(!is_array($subregionNorm))
753 $subregionNorm = Comparator::normalizeEntity($subregion, 'SUBREGION');
754
755 $found = Comparator::isEntityEqual($loc['PARENTS_NAME_UPPER'], $subregionNorm, 'SUBREGION');
756 }
757 elseif($city <> '' && $loc['PARENTS_TYPE_CODE'] == 'CITY')
758 {
759 if(!is_array($cityNorm))
760 $subregionNorm = Comparator::normalizeEntity($city, 'LOCALITY');
761
762 $found = Comparator::isEntityEqual($loc['PARENTS_NAME_UPPER'], $cityNorm, 'LOCALITY');
763 }
764
765 if($found !== null)
766 {
767 $isInExact = in_array($id, $exact);
768 $results[$id][$loc['PARENTS_TYPE_CODE']] = $found;
769
770 if($results[$id]['REGION'] === true && $results[$id]['SUBREGION'] === true && $isInExact)
771 return $id;
772
773 if($found === false && $isInExact)
774 {
775 $key = array_search($id, $exact);
776
777 if($key !== false)
778 unset($exact[$key]);
779 }
780 }
781 }
782 }
783
784 if(!empty($exact))
785 foreach($exact as $e)
786 if(!in_array(false, $results[$e], true))
787 return $e;
788
789 $resCandidates = array();
790
791 foreach($results as $id => $result)
792 {
793 if(!in_array(false, $result, true))
794 {
795 $resCandidates[$id] = count($result);
796 }
797 }
798
799 if(empty($resCandidates))
800 return 0;
801
802 if(count($resCandidates) > 1)
803 {
804 arsort($resCandidates);
805 reset($resCandidates);
806 }
807
808 return key($resCandidates);
809 }
810
811 protected static function getIdByMargin($parentLeft, $parentRight, $lMargins)
812 {
813 $result = array();
814
815 foreach($lMargins as $m)
816 {
817 if($m[1] > $parentLeft && $m[2] < $parentRight)
818 $result[] = $m[0];
819 }
820
821 return $result;
822 }
823
824 protected static function getNameByMargin($parentLeft, $parentRight, $lMargins)
825 {
826 foreach($lMargins as $m)
827 {
828 if($m[1] > $parentLeft && $m[2] < $parentRight)
829 return $m[3];
830 }
831
832 return 0;
833 }
834}
static getNameByMargin($parentLeft, $parentRight, $lMargins)
static setExternalLocation($srvId, $locationId, $xmlId, $updateExist=false)
static setExternalLocation2($srvId, $locationId, $xmlId, $updateExist=false)
static getIdByMargin($parentLeft, $parentRight, $lMargins)
static getUpperCityExternalId($locationId, $srvId)
static getLocationIdByNames($name, $city, $subregion, $region, $country='', $exactOnly=false)
static fillNormalizedTable($startId=false, $timeout=0)
static getLocalityNamesArray($name, $type)