Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
locationhelper.php
1<?php
10
11use Bitrix\Main;
15
16Loc::loadMessages(__FILE__);
17
18final class LocationHelper extends NameHelper
19{
20 const LIST_PAGE_URL = 'sale_location_node_list.php';
21 const EDIT_PAGE_URL = 'sale_location_node_edit.php';
22
23 const MENU_MAX_ITEMS_IN = 100;
24 const MENU_LOCATION_PARENT_TAG = 'menu_sale_location_tree';
25
26 const MENU_ITEMS_QUERY_STRING_TAG = 'menu_sale_location_tree';
28
29 const URL_PARAM_PARENT_ID = 'PARENT_ID';
30 const URL_PARAM_ID = 'id';
31
32 #####################################
33 #### Entity settings
34 #####################################
35
40 public static function getEntityRoadMap()
41 {
42 return array(
43 'main' => array(
44 'name' => 'Bitrix\Sale\Location\Location',
45 'pages' => array(
46 'list' => array(
47 //'excludedColumns' => array('PARENT_ID')
48 ),
49 'detail' => array(
50 'excludedColumns' => array()
51 ),
52 )
53 ),
54 'name' => array(
55 'name' => 'Bitrix\Sale\Location\Name\Location',
56 'pages' => array(
57 'list' => array(
58 'includedColumns' => array('NAME', 'SHORT_NAME')
59 ),
60 'detail' => array(
61 'includedColumns' => array('NAME', 'SHORT_NAME')
62 )
63 )
64 ),
65 'external' => array(
66 'name' => 'Bitrix\Sale\Location\External',
67 'pages' => array(
68 'detail' => array(
69 'includedColumns' => array('ID', 'XML_ID', 'SERVICE_ID')
70 )
71 )
72 ),
73 );
74 }
75
76 ##############################################
77 ##############################################
78 ##############################################
79
80 public static function getFilterColumns()
81 {
82 $columns = static::getColumns('list');
83 foreach($columns as $code => &$col)
84 {
85 $col['DEFAULT'] = in_array($code, array('ID', 'TYPE_ID', 'NAME_'.ToUpper(LANGUAGE_ID), 'SORT'));
86 }
87
88 return $columns;
89 }
90
91 public static function getListGridColumns()
92 {
93 $columns = static::getFilterColumns();
94 unset($columns['PARENT_ID']);
95
96 return $columns;
97 }
98
99 // generalized filter to orm filter proxy
100 public static function getParametersForList($proxed)
101 {
102 $parameters = parent::getParametersForList($proxed);
103
104 if(isset($parameters['order']['TYPE_ID'])) // sorting by TYPE_ID, being set, should work in different way
105 {
106 $parameters['order']['TYPE.SORT'] = $parameters['order']['TYPE_ID'];
107 unset($parameters['order']['TYPE_ID']);
108 }
109
110 return $parameters;
111 }
112
113 public static function getFormData($id)
114 {
115 $formData = parent::getFormData($id);
116
117 // external data as a separate independent table
118 $formData = array_merge($formData, static::getExternalData($id));
119
120 return $formData;
121 }
122
123 ##############################################
124 ##############################################
125 ##############################################
126
127 // high-level validators used when accepting data typed in form. There can be some misspelling, etc, so additional buisness-logic required
128 public static function validateUpdateRequest($data)
129 {
130 $errors = parent::validateUpdateRequest($data);
131
132 // if type is set in data and not empty, it must exist
133 $typeError = false;
134 $typeId = (int)($data['TYPE_ID'] ?? 0);
135 if ($typeId > 0)
136 {
137 $type = Location\TypeTable::getRow([
138 'select' => [
139 'ID'
140 ],
141 'filter' => [
142 '=ID' => $typeId,
143 ],
144 ]);
145
146 if (!$type)
147 {
148 $typeError = true;
149 }
150 }
151 else
152 {
153 $typeError = true;
154 }
155
156 if ($typeError)
157 {
158 $errors[] = Loc::getMessage('SALE_LOCATION_ADMIN_LOCATION_HELPER_ENTITY_TYPE_ID_UNKNOWN_ERROR');
159 }
160
161 // formally check service ids in EXTERNAL parameter
162 if (!empty($data['EXTERNAL']) && is_array($data['EXTERNAL']))
163 {
164 $services = self::getExternalServicesList();
165
166 foreach ($data['EXTERNAL'] as $external)
167 {
168 if (!isset($services[$external['SERVICE_ID']]))
169 {
170 $errors[] = Loc::getMessage('SALE_LOCATION_ADMIN_LOCATION_HELPER_ENTITY_UNKNOWN_EXTERNAL_SERVICE_ID_ERROR');
171 break;
172 }
173 }
174 }
175
176 if (!empty($data['NAME']) && is_array($data['NAME']))
177 {
178 $hasValidName = false;
179
180 foreach($data['NAME'] as $fields)
181 {
182 if (!empty($fields['NAME']))
183 {
184 $hasValidName = true;
185 break;
186 }
187 }
188
189 if (!$hasValidName)
190 {
191 $errors[] = Loc::getMessage('SALE_LOCATION_ADMIN_LOCATION_HELPER_ENTITY_NAME_EMPTY_ERROR');
192 }
193 }
194
195 return $errors;
196 }
197
198 public static function proxyUpdateRequest($data)
199 {
200 $externals = $data['EXTERNAL'];
201 unset($data['EXTERNAL']);
202
203 if(is_array($externals) && !empty($externals))
204 {
205 foreach($externals as $eId => $external)
206 {
207 if($external['XML_ID'] == '')
208 unset($externals[$eId]);
209 }
210 }
211
212 $data = parent::proxyUpdateRequest($data);
213
214 if(!empty($externals))
215 $data['EXTERNAL'] = $externals;
216
217 return $data;
218 }
219
220 public static function proxyListRequest($page = 'list')
221 {
222 $parameters = parent::proxyListRequest($page);
223
224 if($page == 'list') // filter by parent_id in list
225 {
226 if(!isset($parameters['filter']['=PARENT_ID'])) // value has not came from filter
227 {
228 if (isset($_REQUEST['PARENT_ID']) && !Context::isInternalRequest())
229 $parameters['filter']['=PARENT_ID'] = intval($_REQUEST['PARENT_ID']);
230 else
231 $parameters['filter']['=PARENT_ID'] = 0;
232 }
233 }
234
235 if(isset($parameters['order']['TYPE_ID'])) // sorting by TYPE_ID, being set, should work in different way
236 {
237 $parameters['order']['TYPE.SORT'] = $parameters['order']['TYPE_ID'];
238 unset($parameters['order']['TYPE_ID']);
239 }
240
241 return $parameters;
242 }
243
244 // crud over entity: update
245 public static function update($primary, $data, $batch = false)
246 {
247 $success = true;
248 $entityClass = static::getEntityClass();
249
250 $data = static::convertToArray($data);
251 $data = static::proxyUpdateRequest($data);
252 $errors = static::validateUpdateRequest($data);
253
254 if(empty($errors))
255 {
256 $res = $entityClass::update($primary, $data, array('RESET_LEGACY' => !$batch));
257 if(!$res->isSuccess())
258 {
259 $success = false;
260 $errors = $res->getErrorMessages();
261 }
262 }
263 else
264 $success = false;
265
266 return array(
267 'success' => $success,
268 'errors' => $errors
269 );
270 }
271
272 // crud over entity: delete
273 public static function delete($primary, $batch = false)
274 {
275 $success = true;
276 $errors = array();
277 $entityClass = static::getEntityClass();
278
279 $res = $entityClass::deleteExtended($primary, array('RESET_LEGACY' => !$batch));
280 if(!$res->isSuccess())
281 {
282 $success = false;
283 $errors = $res->getErrorMessages();
284 }
285
286 return array(
287 'success' => $success,
288 'errors' => $errors
289 );
290 }
291
292 #####################################
293 #### Entity-specific
294 #####################################
295
296 public static function checkFirstImportDone()
297 {
298 return \Bitrix\Main\Config\Option::get('sale', 'sale_locationpro_import_performed', '') == 'Y';
299 }
300
301 public static function getParentId($id)
302 {
303 if(!($id = intval($id)))
304 return 0;
305
306 $class = static::getEntityClass('main');
307 $item = $class::getList(array(
308 'filter' => array('=ID' => $id),
309 'select' => array('PARENT_ID')
310 ))->fetch();
311
312 return $item['PARENT_ID'];
313 }
314
315 public static function getExternalData($id)
316 {
317 $res = Location\LocationTable::getExternalData($id);
318 $result = array();
319 while($item = $res->Fetch())
320 $result['EXTERNAL'][$item['ID']] = $item;
321
322 return $result;
323 }
324
325 public static function getExternalServicesList()
326 {
327 static $services;
328
329 if($services == null)
330 {
331 $res = Location\ExternalServiceTable::getList();
332 $services = array();
333 while($item = $res->Fetch())
334 $services[$item['ID']] = $item;
335 }
336
337 return $services;
338 }
339
343 public static function getYandexMarketExternalServiceId(): int
344 {
345 static $result;
346
347 if ($result === null)
348 {
349 $result = 0;
350
351 $yandexMarketEs = Location\ExternalServiceTable::getList([
352 'filter' => ['=CODE' => \CSaleYMLocation::EXTERNAL_SERVICE_CODE]
353 ])->fetch();
354
355 if ($yandexMarketEs)
356 {
357 $result = (int)$yandexMarketEs['ID'];
358 }
359 }
360
361 return $result;
362 }
363
369 public static function getTypeList()
370 {
371 static $types;
372
373 if($types == null)
374 {
375 $types = array();
376 $typesWithNames = Location\Admin\TypeHelper::getTypes();
377 foreach($typesWithNames as $type)
378 {
379 $types[intval($type['ID'])] = $type['NAME_CURRENT'];
380 }
381 }
382
383 return $types;
384 }
385
386 public static function getExternalMap()
387 {
388 return static::readMap('external', 'detail');
389 }
390
391 public static function checkRequestIsMenuRequest()
392 {
393 return mb_strpos(($_REQUEST['admin_mnu_menu_id'] ?? ''), self::MENU_ITEMS_QUERY_STRING_TAG) !== false;
394 }
395
396 public static function getLocationSubMenu()
397 {
398 // how it works: every time when we call for the next sub-level, we must
399 // obtain not sublevel itself, but a whole parent-tree of it
400
401 $queryParams = self::unPackItemsQueryString();
402
403 $requiredToShow = false;
404 // three situations:
405 // 1) node id comes in $_REQUEST['admin_mnu_menu_id'] parameter when user walks along left menu tree
406 $id = false;
407 if(self::checkRequestIsMenuRequest())
408 {
409 $requiredToShow = true;
410 $id = $queryParams['ID'];
411 }
412 if(!$id)
413 {
414 // 2) node id comes in $_REQUEST['id'] or in $_REQUEST['parent_id'] when user enters self::LIST_PAGE_URL or self::EDIT_PAGE_URL page
415 $page = $GLOBALS['APPLICATION']->GetCurPage();
416 if($page == '/bitrix/admin/'.self::LIST_PAGE_URL || $page == '/bitrix/admin/'.self::EDIT_PAGE_URL)
417 {
418 $requiredToShow = true;
419
420 $parentId = (int)($_REQUEST['PARENT_ID'] ?? 0);
421 if ($parentId <= 0)
422 {
423 $parentId = (int)($_REQUEST['parent_id'] ?? 0);
424 }
425 if ($parentId > 0)
426 {
427 $id = $parentId;
428 }
429 }
430 }
431 // 3) there is no node id at all
432
433 $tree = array();
434 if($requiredToShow)
435 {
436 $parameters = array(
437 'select' => array(
438 'ID',
439 'LOCATION_NAME' => 'NAME.NAME',
440 'DEPTH_LEVEL',
441 'PARENT_ID',
442 'CHILD_CNT'
443 ),
444 'filter' => array(
445 '=NAME.LANGUAGE_ID' => LANGUAGE_ID
446 ),
447 'order' => array(
448 'LOCATION_NAME' => 'asc' // result always come sorted by LEFT_MARGIN, we must resort it by NAME
449 )
450 );
451
452 if($id)
453 {
454 try
455 {
456 $res = Location\LocationTable::getParentTree($id, $parameters, array('SHOW_CHILDREN' => true));
457 }
458 catch(Main\SystemException $e)
459 {
460 return array();
461 }
462 }
463 else
464 {
465 $res = Location\LocationTable::getChildren(false, $parameters);
466 }
467
468 $index = array();
469 while($item = $res->Fetch())
470 {
471 $index[$item['PARENT_ID']][$item['ID']] = array(
472 'NAME' => htmlspecialcharsbx($item['LOCATION_NAME']),
473 'PARENT_ID' => intval($item['PARENT_ID']),
474 'CHILD_CNT' => intval($item['CHILD_CNT'])
475 );
476 }
477
478 unset($res);
479 unset($item);
480
481 self::appendMenuChildren($tree, 0, $index, $queryParams);
482 }
483
484 return $tree;
485 }
486
487 // transcendental thing that makes location menu work
488 public static function packItemsQueryString($parameters = array())
489 {
490 $inRequest = self::unPackItemsQueryString();
491
492 $query = array(self::MENU_ITEMS_QUERY_STRING_TAG, intval($parameters['ID']));
493 if(isset($parameters['LIMIT'])) // limit taken from the argument
494 $query[] = intval($parameters['LIMIT']);
495 else
496 {
497 if(self::checkRequestIsMenuRequest() && isset($inRequest['LIMIT'])) // limit taken from request
498 $query[] = intval($inRequest['LIMIT']);
499 else // limit taken by default
500 $query[] = self::MENU_MAX_ITEMS_IN;
501 }
502
503 if(isset($parameters['SHOW_CHECKBOX']))
504 $query[] = $parameters['SHOW_CHECKBOX'] ? '1' : '0';
505 else
506 {
507 if(self::checkRequestIsMenuRequest() && isset($inRequest['SHOW_CHECKBOX']))
508 $query[] = $inRequest['SHOW_CHECKBOX'] ? '1' : '0';
509 else
510 $query[] = '0';
511 }
512
513 return implode(self::MENU_ITEMS_QUERY_STRING_DELIMITER, $query);
514 }
515
516 public static function unPackItemsQueryString()
517 {
518 $path = explode(self::MENU_ITEMS_QUERY_STRING_DELIMITER, ($_REQUEST['admin_mnu_menu_id'] ?? ''));
519
520 return array(
521 'ID' => (isset($path[1]) && intval($path[1])) ? intval($path[1]) : false,
522 'LIMIT' => isset($path[2]) ? intval($path[2]) : 0,
523 'SHOW_CHECKBOX' => isset($path[3]) ? (!!$path[3]) : false,
524 );
525 }
526
527 public static function getListUrl($parent = false, $parameters = array())
528 {
529 if(!is_array($parameters))
530 $parameters = array();
531
532 if($parent !== false)
533 {
534 //$parameters['filter'] = 'Y';
535 //$parameters['set_filter'] = 'Y';
536 $parameters[static::URL_PARAM_PARENT_ID] = intval($parent);
537 //$parameters['adm_filter_applied'] = '0';
538 }
539
540 return parent::getListUrl($parameters);
541 }
542
543 public static function getEditUrl($node = false, $parameters = array())
544 {
545 if(!is_array($parameters))
546 $parameters = array();
547
548 if($node != false)
549 $parameters[static::URL_PARAM_ID] = $node;
550
551 return self::getUrl(static::EDIT_PAGE_URL, $parameters);
552 }
553
554 public static function appendMenuChildren(&$attachTo, $attachWhat, $index, $queryParams)
555 {
556 $i = 0;
557 $overflow = false;
558 $inChain = false;
559 $limit = self::MENU_MAX_ITEMS_IN; // set always limited to self::MENU_MAX_ITEMS_IN (originally was intval($queryParams['LIMIT']));
560
561 if(empty($index))
562 return;
563
564 if(is_array($index[$attachWhat]))
565 {
566 foreach($index[$attachWhat] as $id => $item)
567 {
568 if($limit && (!$overflow && $i >= $limit) || ($overflow && $inChain/* the previous item was significant */))
569 {
570 $overflow = true;
571
572 $attachTo[] = array(
573 "text" => Loc::getMessage("SALE_MENU_LOCATION_THE_REST_OF"),
574 "url" => static::getListUrl(intval($item['PARENT_ID'])),
575 "module_id" => "sale",
576 "parent_menu" => self::packItemsQueryString(array('ID' => $item['PARENT_ID'], 'LIMIT' => $limit, 'SHOW_CHECKBOX' => $queryParams['SHOW_CHECKBOX'])),
577 );
578 }
579
580 $inChain = isset($index[$id]); // this is important node - it belongs to the chain being displayed
581
582 if(!$overflow || $inChain)
583 {
584 $node = array(
585 "text" => ($queryParams['SHOW_CHECKBOX'] ? '<input type="checkbox" value="'.intval($id).'" />&nbsp;' : '').$item['NAME'],
586 "fav_id" => intval($id), // allows javascript to know what item it is
587 "url" => \CHTTP::urlAddParams(static::getListUrl(intval($id)), ["apply_filter" => "y"]),
588 "module_id" => "sale",
589 "items_id" => self::packItemsQueryString(array('ID' => $id, 'LIMIT' => $limit, 'SHOW_CHECKBOX' => $queryParams['SHOW_CHECKBOX'])),
590 //"skip_chain" => true, // uncomment, if you dont want this menu item figure in breadcrumbs
591 "parent_menu" => self::packItemsQueryString(array('ID' => $item['PARENT_ID'], 'LIMIT' => $limit, 'SHOW_CHECKBOX' => $queryParams['SHOW_CHECKBOX'])),
592 "more_url" => array( // additional route, which will be treated as an alias when calculating selected menu path
593 self::getEditUrl(intval($id)), // when editing existed node
594 self::getEditUrl(false, array('parent_id' => intval($id))) // when adding a new node
595 )
596 );
597
598 if($item['CHILD_CNT'])
599 {
600 $node['dynamic'] = true;
601 $node['items'] = array();
602
603 if($inChain)
604 self::appendMenuChildren($node['items'], $id, $index, $queryParams);
605 }
606
607 $attachTo[] = $node;
608
609 }
610 $i++;
611 }
612 }
613 }
614
615 public static function getLocationStringById($primary, $behaviour = array('INVERSE' => false, 'DELIMITER' => ', ', 'LANGUAGE_ID' => LANGUAGE_ID))
616 {
617 return static::getLocationStringByCondition(array('=ID' => $primary), $behaviour);
618 }
619
620 public static function getLocationStringByCode($primary, $behaviour = array('INVERSE' => false, 'DELIMITER' => ', ', 'LANGUAGE_ID' => LANGUAGE_ID))
621 {
622 return static::getLocationStringByCondition(array('=CODE' => $primary), $behaviour);
623 }
624
625 protected static function getLocationStringByCondition($condition, $behaviour = array('INVERSE' => false, 'DELIMITER' => ', ', 'LANGUAGE_ID' => LANGUAGE_ID))
626 {
627 if(isset($behaviour) && !is_array($behaviour))
628 $behaviour = array();
629
630 if(!isset($behaviour['DELIMITER']))
631 $behaviour['DELIMITER'] = ', ';
632
633 if(!isset($behaviour['LANGUAGE_ID']))
634 $behaviour['LANGUAGE_ID'] = LANGUAGE_ID;
635
636 try
637 {
638 $res = Location\LocationTable::getPathToNodeByCondition($condition, array('select' => array('LNAME' => 'NAME.NAME'), 'filter' => array('=NAME.LANGUAGE_ID' => $behaviour['LANGUAGE_ID'])));
639 $path = array();
640 while($item = $res->fetch())
641 {
642 $path[] = $item['LNAME'];
643 }
644
645 if($behaviour['INVERSE'])
646 $path = array_reverse($path);
647
648 return implode($behaviour['DELIMITER'], $path);
649 }
650 catch(\Bitrix\Main\SystemException $e)
651 {
652 return '';
653 }
654 }
655
656 public static function getLocationsByZip($zip, $parameters = array())
657 {
658 $zip = trim($zip);
659
660 if(!is_array($parameters))
661 $parameters = array();
662
663 $parameters['filter'][] = array(
664 'LOGIC' => 'OR',
665 array('=SERVICE.CODE' => 'ZIP'),
666 array('=SERVICE.CODE' => 'ZIP_LOWER')
667 );
668
669 $parameters['filter']['=XML_ID'] = $zip;
670 $parameters['order']['SERVICE_CODE'] = 'ASC';
671 $parameters['select'][] = '*';
672 $parameters['select']['SERVICE_CODE'] = 'SERVICE.CODE';
673
674 return \Bitrix\Sale\Location\ExternalTable::getList($parameters);
675 }
676
677 public static function getZipByLocation($locationCode, $parameters = array())
678 {
679 if($locationCode == '')
680 return new \Bitrix\Main\DB\ArrayResult(array());
681
682 if(!is_array($parameters))
683 $parameters = array();
684
685 $parameters['filter'][] = array(
686 'LOGIC' => 'OR',
687 array('=SERVICE.CODE' => 'ZIP'),
688 array('=SERVICE.CODE' => 'ZIP_LOWER')
689 );
690 $parameters['order']['SERVICE_CODE'] = 'ASC';
691 $parameters['filter']['=LOCATION.CODE'] = $locationCode;
692 $parameters['select'][] = '*';
693 $parameters['select']['SERVICE_CODE'] = 'SERVICE.CODE';
694
695 return \Bitrix\Sale\Location\ExternalTable::getList($parameters);
696 }
697
698 public static function checkLocationMigrated()
699 {
700 return Main\Config\Option::get('sale', 'sale_locationpro_migrated', '') == 'Y';
701 }
702
703 // checks if new location enabled or not
704 public static function checkLocationEnabled()
705 {
706 return static::checkLocationMigrated();
707 }
708
709 // informers
710 public static function informAdminLocationDatabaseFailure()
711 {
712 static::deleteInformer('SALE_LOCATIONPRO_DATABASE_FAILURE');
713
714 $fields = array(
715 "MESSAGE" => Loc::getMessage('SALE_LOCATION_ADMIN_LOCATION_HELPER_DATABASE_FAILURE', array(
716 '#ANCHOR_IMPORT_URL#' => '<a target="_blank" href="'.static::getImportUrl().'">',
717 '#ANCHOR_END#' => '</a>'
718 )),
719 "TAG" => 'SALE_LOCATIONPRO_DATABASE_FAILURE',
720 "MODULE_ID" => "sale",
721 "ENABLE_CLOSE" => "Y",
722 "PUBLIC_SECTION" => "N"
723 );
724 \CAdminNotify::Add($fields);
725 }
726 public static function deleteInformer($informerTag)
727 {
728 if((string) $informerTag == '')
729 return;
730
731 $rsAdminNotify = \CAdminNotify::GetList(array(), array('MODULE_ID'=>'sale', 'TAG' => $informerTag));
732 if ($arAdminNotify = $rsAdminNotify->Fetch())
733 {
734 \CAdminNotify::DeleteByTag($informerTag);
735 }
736 }
737
741 public static function getLocationPathDisplay($primary)
742 {
743 if($primary == '')
744 return '';
745
746 if((string) $primary === (string) intval($primary))
747 return static::getLocationStringById($primary);
748 else
749 return static::getLocationStringByCode($primary);
750 }
751}
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getLocationsByZip($zip, $parameters=array())
static getLocationStringByCode($primary, $behaviour=array('INVERSE'=> false, 'DELIMITER'=> ', ', 'LANGUAGE_ID'=> LANGUAGE_ID))
static getListUrl($parent=false, $parameters=array())
static appendMenuChildren(&$attachTo, $attachWhat, $index, $queryParams)
static update($primary, $data, $batch=false)
static getZipByLocation($locationCode, $parameters=array())
static getLocationStringByCondition($condition, $behaviour=array('INVERSE'=> false, 'DELIMITER'=> ', ', 'LANGUAGE_ID'=> LANGUAGE_ID))
static packItemsQueryString($parameters=array())
static getLocationStringById($primary, $behaviour=array('INVERSE'=> false, 'DELIMITER'=> ', ', 'LANGUAGE_ID'=> LANGUAGE_ID))
static getEditUrl($node=false, $parameters=array())
$GLOBALS['____1444769544']
Definition license.php:1