Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
finder.php
1<?php
9
10use Bitrix\Main;
14
17
18Loc::loadMessages(__FILE__);
19
20class Finder
21{
22 const SALE_LOCATION_INDEXED_TYPES_OPT = 'sale.location.indexed_types';
23 const SALE_LOCATION_INDEXED_LANGUAGES_OPT = 'sale.location.indexed_langs';
24 const SALE_LOCATION_INDEX_VALID_OPT = 'sale.location.index_valid';
25
26 protected static $allowedOperations = array(
27 '=' => true
28 );
29
30 public static function checkIndexValid()
31 {
32 return Option::get('sale', self::SALE_LOCATION_INDEX_VALID_OPT, '', '') == 'Y';
33 }
34
35 public static function setIndexValid()
36 {
37 Option::set('sale', self::SALE_LOCATION_INDEX_VALID_OPT, 'Y', '');
38 }
39
40 public static function setIndexInvalid()
41 {
42 Option::set('sale', self::SALE_LOCATION_INDEX_VALID_OPT, 'N', '');
43 }
44
45 public static function getIndexedTypes()
46 {
47 $types = Option::get('sale', self::SALE_LOCATION_INDEXED_TYPES_OPT, '', '');
48 $typesFromDb = static::getTypesFromDb();
49
50 if($types == '') // means "all"
51 return array_keys($typesFromDb);
52
53 $types = explode(':', $types);
54 $result = array();
55
56 if(is_array($types))
57 {
58 foreach($types as $type)
59 {
60 $type = intval($type);
61 if(isset($typesFromDb[$type]))
62 $result[] = $type;
63 }
64 }
65
66 return array_unique($result);
67 }
68
69 public static function setIndexedTypes($types = array())
70 {
71 $result = array();
72 if(is_array($types) && !empty($types))
73 {
74 $typesFromDb = static::getTypesFromDb();
75
76 foreach($types as $type)
77 {
78 $type = intval($type);
79 if(isset($typesFromDb[$type]))
80 $result[] = $type;
81 }
82
83 $result = array_unique($result);
84 }
85
86 Option::set('sale', self::SALE_LOCATION_INDEXED_TYPES_OPT, implode(':', $result), '');
87 }
88
89 public static function getIndexedLanguages()
90 {
91 $langs = Option::get('sale', self::SALE_LOCATION_INDEXED_LANGUAGES_OPT, '', '');
92 $langsFromDb = static::getLangsFromDb();
93
94 if($langs == '')
95 return array_keys($langsFromDb);
96
97 $result = array();
98 $langs = explode(':', $langs);
99
100 if(is_array($langs))
101 {
102 foreach($langs as $lang)
103 {
104 if(isset($langsFromDb[$lang]))
105 $result[] = $lang;
106 }
107 }
108
109 return array_unique($result);
110 }
111
112 public static function setIndexedLanguages($langs = array())
113 {
114 if(is_array($langs) && !empty($langs))
115 $langs = array_unique($langs);
116 else
117 $langs = array();
118
119 $result = array();
120 if(is_array($langs) && !empty($langs))
121 {
122 $langsFromDb = static::getLangsFromDb();
123
124 foreach($langs as $lang)
125 {
126 if(isset($langsFromDb[$lang]))
127 $result[] = $lang;
128 }
129
130 $result = array_unique($result);
131 }
132
133 Option::set('sale', self::SALE_LOCATION_INDEXED_LANGUAGES_OPT, implode(':', $result), '');
134 }
135
136 protected static function getLangsFromDb()
137 {
138 $langsFromDb = array();
139 $res = \Bitrix\Main\Localization\LanguageTable::getList(array('select' => array('ID')));
140 while($item = $res->fetch())
141 $langsFromDb[$item['ID']] = true;
142
143 return $langsFromDb;
144 }
145
146 protected static function getTypesFromDb()
147 {
148 $typesFromDb = array();
149 $res = Location\TypeTable::getList(array('select' => array('ID')));
150 while($item = $res->fetch())
151 $typesFromDb[intval($item['ID'])] = true;
152
153 return $typesFromDb;
154 }
155
162 public static function find(
163 $parameters,
164 $behaviour = ['FALLBACK_TO_NOINDEX_ON_NOTFOUND' => true, 'USE_INDEX' => true, 'USE_ORM' => true]
165 )
166 {
168 // parameter check and process
169
170 Assert::expectArray($parameters, '$parameters');
171
172 if(!is_array($behaviour))
173 $behaviour = array();
174 if(!isset($behaviour['FALLBACK_TO_NOINDEX_ON_NOTFOUND']))
175 $behaviour['FALLBACK_TO_NOINDEX_ON_NOTFOUND'] = true;
176 if(!isset($behaviour['USE_INDEX']))
177 $behaviour['USE_INDEX'] = true;
178 if(!isset($behaviour['USE_ORM']))
179 $behaviour['USE_ORM'] = true;
180
181 if(!isset($parameters['select']))
182 $parameters['select'] = array('ID');
183
184 Assert::expectArray($parameters['select'], '$parameters[select]');
185
186 if(isset($parameters['filter']))
187 {
188 Assert::expectArray($parameters['filter'], '$parameters[filter]');
189
190 // spikes, refactor later
191
192 if(isset($parameters['filter']['PHRASE']) || isset($parameters['filter']['=PHRASE']))
193 {
194 $key = isset($parameters['filter']['PHRASE']) ? 'PHRASE' : '=PHRASE';
195
196 $parameters['filter'][$key] = Assert::expectStringNotNull($parameters['filter'][$key], '$parameters[filter]['.$key.']');
197 $parameters['filter'][$key] = str_replace('%', '', $parameters['filter'][$key]); // cannot pass '%' to like
198 }
199
200 if(isset($parameters['filter']['SITE_ID']) || isset($parameters['filter']['=SITE_ID']))
201 {
202 $key = isset($parameters['filter']['SITE_ID']) ? 'SITE_ID' : '=SITE_ID';
203 $parameters['filter'][$key] = Assert::expectStringNotNull($parameters['filter'][$key], '$parameters[filter]['.$key.']'); // stronger here
204
205 if(!Location\SiteLocationTable::checkLinkUsageAny($parameters['filter'][$key]))
206 unset($parameters['filter'][$key]);
207 }
208 }
209
210 if(isset($parameters['limit']))
211 $parameters['limit'] = Assert::expectIntegerNonNegative($parameters['limit'], '$parameters[limit]');
212 if(isset($parameters['offset']))
213 $parameters['offset'] = Assert::expectIntegerNonNegative($parameters['offset'], '$parameters[offset]');
214
216
217 if(
218 (isset($parameters['filter']['PHRASE']) || isset($parameters['filter']['SITE_ID']) || isset($parameters['filter']['=PHRASE']) || isset($parameters['filter']['=SITE_ID']))
219 ||
220 $behaviour['USE_ORM'] === false
221 )
222 {
223 if(static::checkIndexValid() && $behaviour['USE_INDEX'])
224 {
225 $result = static::findUsingIndex($parameters);
226 if(!$behaviour['FALLBACK_TO_NOINDEX_ON_NOTFOUND'])
227 {
228 return $result;
229 }
230 else
231 {
232 $temporalBuffer = array();
233 while($item = $result->fetch())
234 {
235 $temporalBuffer[] = $item;
236 }
237
238 if(empty($temporalBuffer))
239 {
240 return static::findNoIndex($parameters);
241 }
242 else
243 {
244 return new DB\ArrayResult($temporalBuffer);
245 }
246 }
247 }
248 else
249 {
250 return static::findNoIndex($parameters);
251 }
252 }
253 else
254 {
255 return Location\LocationTable::getList($parameters);
256 }
257 }
258
259 protected static function parseFilter($filter)
260 {
261 $parsed = array();
262
263 if(is_array($filter))
264 {
265 foreach($filter as $field => $value)
266 {
267 $found = array();
268 preg_match("#^(=?)(.+)#", $field, $found);
269
270 if($found[1] <> '')
271 {
272 $op = $found[1];
273 }
274 else
275 {
276 $op = '=';
277 }
278
279 if(!isset(static::$allowedOperations[$op]))
280 throw new Main\ArgumentException('Unknown modifier in the filter');
281
282 $fieldParsed = $found[2];
283
284 $parsed[$fieldParsed] = array(
285 'OP' => $op <> ''? $op : '=',
286 'VALUE' => $value
287 );
288 }
289 }
290
291 return $parsed;
292 }
293
294 protected static function findUsingIndex($parameters)
295 {
296 $query = array();
297
298 $dbConnection = Main\HttpApplication::getConnection();
299 $dbHelper = Main\HttpApplication::getConnection()->getSqlHelper();
300
301 $filter = static::parseFilter($parameters['filter']);
302
303 $filterByPhrase = isset($filter['PHRASE']) && mb_strlen($filter['PHRASE']['VALUE']);
304
305 if($filterByPhrase) // filter by phrase
306 {
307 $bounds = WordTable::getBoundsForPhrase($filter['PHRASE']['VALUE']);
308 if (!empty($bounds))
309 {
310 $firstBound = array_shift($bounds);
311 $k = 0;
312 foreach($bounds as $bound)
313 {
314 $query['JOIN'][] = " inner join ".ChainTable::getTableName()." A".$k." on A.LOCATION_ID = A".$k.".LOCATION_ID and (
315
316 ".($bound['INF'] == $bound['SUP']
317 ? " A".$k.".POSITION = '".$bound['INF']."'"
318 : " A".$k.".POSITION >= '".$bound['INF']."' and A".$k.".POSITION <= '".$bound['SUP']."'"
319 )."
320 )";
321 $k++;
322 }
323
324 $query['WHERE'][] = (
325 $firstBound['INF'] == $firstBound['SUP']
326 ? " A.POSITION = '".$firstBound['INF']."'"
327 : " A.POSITION >= '".$firstBound['INF']."' and A.POSITION <= '".$firstBound['SUP']."'"
328 );
329 }
330
331 $mainTableJoinCondition = 'A.LOCATION_ID';
332 }
333 else
334 {
335 $mainTableJoinCondition = 'L.ID';
336 }
337
338 // site link search
339 if (
340 isset($filter['SITE_ID']['VALUE'])
341 && is_string($filter['SITE_ID']['VALUE'])
342 && $filter['SITE_ID']['VALUE'] !== ''
344 )
345 {
346 $query['JOIN'][] = "inner join ".SiteLinkTable::getTableName()." SL on SL.LOCATION_ID = ".$mainTableJoinCondition." and SL.SITE_ID = '".$dbHelper->forSql($filter['SITE_ID']['VALUE'])."'";
347 }
348
349 // process filter and select statements
350 // at least, we support here basic field selection and filtration + NAME.NAME and NAME.LANGUAGE_ID
351
352 $map = Location\LocationTable::getMap();
353 $nameRequired = false;
354 $locationRequired = false;
355
356 if(is_array($parameters['select']))
357 {
358 foreach($parameters['select'] as $alias => $field)
359 {
360 if($field == 'NAME.NAME' || $field == 'NAME.LANGUAGE_ID')
361 {
362 $nameRequired = true;
363 continue;
364 }
365
366 if(
367 !isset($map[$field]) ||
368 !in_array($map[$field]['data_type'], array('integer', 'string', 'float', 'boolean')) ||
369 isset($map[$field]['expression'])
370 )
371 {
372 unset($parameters['select'][$alias]);
373 }
374
375 $locationRequired = true;
376 }
377 }
378
379 foreach($filter as $field => $params)
380 {
381 if($field == 'NAME.NAME' || $field == 'NAME.LANGUAGE_ID')
382 {
383 $nameRequired = true;
384 continue;
385 }
386
387 if(
388 !isset($map[$field]) ||
389 !in_array($map[$field]['data_type'], array('integer', 'string', 'float', 'boolean')) ||
390 isset($map[$field]['expression'])
391 )
392 {
393 unset($filter[$field]);
394 }
395
396 $locationRequired = true;
397 }
398
399 // data join, only if extended select specified
400
401 if($locationRequired && $filterByPhrase)
402 $query['JOIN'][] = "inner join ".Location\LocationTable::getTableName()." L on A.LOCATION_ID = L.ID";
403
404 if($nameRequired)
405 $query['JOIN'][] = "inner join ".Location\Name\LocationTable::getTableName()." NAME on NAME.LOCATION_ID = ".$mainTableJoinCondition; // and N.LANGUAGE_ID = 'ru'
406
407 // making select
408 if(is_array($parameters['select']))
409 {
410 $select = array();
411 foreach($parameters['select'] as $alias => $field)
412 {
413 if($field != 'NAME.NAME' && $field != 'NAME.LANGUAGE_ID')
414 $field = 'L.'.$dbHelper->forSql($field);
415
416 if((string) $alias === (string) intval($alias))
417 $select[] = $field;
418 else
419 $select[] = $field.' as '.$dbHelper->forSql($alias);
420 }
421
422 $sqlSelect = implode(', ', $select);
423 }
424 else
425 $sqlSelect = $mainTableJoinCondition.' as ID';
426
427 // making filter
428 foreach($filter as $field => $params)
429 {
430 if($field != 'NAME.NAME' && $field != 'NAME.LANGUAGE_ID')
431 $field = 'L.'.$dbHelper->forSql($field);
432
433 $values = $params['VALUE'];
434
435 if(!is_array($values))
436 $values = array($values);
437
438 foreach($values as $value)
439 $query['WHERE'][] = $field.' '.$params['OP']." '".$dbHelper->forSql($value)."'";
440 }
441
442 if($filterByPhrase)
443 {
444 $sql = "
445 select ".($dbConnection->getType() != 'mysql' ? '' : 'distinct')/*fix this in more clever way later*/."
446 ".$sqlSelect.(\Bitrix\Sale\Location\DB\Helper::needSelectFieldsInOrderByWhenDistinct() ? ', A.RELEVANCY' : '')."
447
448 from ".ChainTable::getTableName()." A
449
450 ".implode(' ', $query['JOIN'])."
451
452 ".(!empty($query['WHERE']) ? 'where ' : '').implode(' and ', $query['WHERE'])."
453
454 order by A.RELEVANCY asc
455 ";
456 }
457 else
458 {
459 $sql = "
460
461 select
462 ".$sqlSelect."
463
464 from ".Location\LocationTable::getTableName()." L
465
466 ".implode(' ', $query['JOIN'])."
467
468 ".(!empty($query['WHERE']) ? 'where ' : '').implode(' and ', $query['WHERE'])."
469 ";
470 }
471
472 $offset = (int)($parameters['offset'] ?? 0);
473 $limit = (int)($parameters['limit'] ?? 0);
474
475 if ($limit)
476 {
477 $sql = $dbHelper->getTopSql($sql, $limit, $offset);
478 }
479
480 return $dbConnection->query($sql);
481 }
482
490 protected static function findNoIndex($parameters)
491 {
492 $dbConnection = Main\HttpApplication::getConnection();
493 $dbHelper = $dbConnection->getSqlHelper();
494
495 // tables
496 $locationTable = Location\LocationTable::getTableName();
497 $locationNameTable = Location\Name\LocationTable::getTableName();
498 $locationGroupTable = Location\GroupLocationTable::getTableName();
499 $locationSiteTable = Location\SiteLocationTable::getTableName();
500 $locationTypeTable = Location\TypeTable::getTableName();
501
503 // sql parameters prepare
505
506 $filter = static::parseFilter($parameters['filter']);
507
508 $doFilterBySite = false;
509 $hasLocLinks = false;
510 $hasGrpLinks = false;
511 if (($filter['SITE_ID']['VALUE'] ?? '') !== '')
512 {
513 $filterSite = $dbHelper->forSql(mb_substr($filter['SITE_ID']['VALUE'], 0, 2));
514
515 $hasLocLinks = Location\SiteLocationTable::checkLinkUsage($filterSite, Location\SiteLocationTable::DB_LOCATION_FLAG);
516 $hasGrpLinks = Location\SiteLocationTable::checkLinkUsage($filterSite, Location\SiteLocationTable::DB_GROUP_FLAG);
517 $doFilterBySite = true;
518 }
519
520 $doFilterByName = false;
521 $filterName = '';
522 $phrase = (string)($filter['PHRASE']['VALUE'] ?? '');
523 if ($phrase !== '')
524 {
525 $doFilterByName = true;
526 $filterName = $dbHelper->forSql(mb_strtoupper($phrase));
527 }
528
529 $doFilterById = false;
530 $filterId = null;
531 if (isset($filter['ID']))
532 {
533 if (is_array($filter['ID']['VALUE']))
534 {
535 $doFilterById = true;
536
537 if (count($filter['ID']['VALUE']) === 1)
538 {
539 reset($filter['ID']['VALUE']);
540 $filterId = (int)current($filter['ID']['VALUE']);
541 }
542 else
543 {
544 $filterId = $filter['ID']['VALUE'];
545 }
546 }
547 elseif ((int)$filter['ID']['VALUE'])
548 {
549 $doFilterById = true;
550 $filterId = (int)$filter['ID']['VALUE'];
551 }
552 }
553
554 $doFilterByCode = false;
555 $filterCode = '';
556 $codeValue = (int)($filter['CODE']['VALUE'] ?? 0);
557 if ($codeValue)
558 {
559 $doFilterByCode = true;
560 $filterCode = $dbHelper->forSql((string)$codeValue);
561 }
562 unset($codeValue);
563
564 if (($filter['NAME.LANGUAGE_ID']['VALUE'] ?? '') !== '')
565 {
566 $filterLang = $dbHelper->forSql(mb_substr((string)$filter['NAME.LANGUAGE_ID']['VALUE'], 0, 2));
567 }
568 else
569 {
570 $filterLang = LANGUAGE_ID;
571 }
572
573 $doFilterByCountry = false;
574 $filterCountryId = 0;
575 if (isset($filter['COUNTRY_ID']) && (int)$filter['COUNTRY_ID']['VALUE'] >= 0)
576 {
577 $doFilterByCountry = true;
578 $filterCountryId = (int)$filter['COUNTRY_ID']['VALUE'];
579 }
580
581 $doFilterByParent = false;
582 $filterParentId = 0;
583 if (isset($filter['PARENT_ID']) && (int)$filter['PARENT_ID']['VALUE'] >= 0)
584 {
585 $doFilterByParent = true;
586 $filterParentId = (int)$filter['PARENT_ID']['VALUE'];
587 }
588
589 $doFilterByType = false;
590 $filterTypeId = 0;
591 if ((int)($filter['TYPE_ID']['VALUE'] ?? 0))
592 {
593 $doFilterByType = true;
594 $filterTypeId = (int)$filter['TYPE_ID']['VALUE'];
595 }
596
597 // filter select fields
598 $parameters['select'] ??= [];
599 if(!is_array($parameters['select']))
600 {
601 $parameters['select'] = [];
602 }
603
604 $doCountChildren = false;
605 $map = Location\LocationTable::getMap();
606 $nameAlias = false;
607 $allowTypes = [
608 'integer' => true,
609 'string' => true,
610 'float' => true,
611 'boolean' => true,
612 ];
613 foreach($parameters['select'] as $alias => $field)
614 {
615 if ($field === 'CHILD_CNT')
616 {
617 $doCountChildren = true;
618 }
619
620 if ($field === 'NAME.NAME')
621 {
622 $nameAlias = $alias;
623 }
624
625 $badField = false;
626 if (!isset($map[$field]))
627 {
628 $badField = true;
629 }
630 elseif (
631 !isset($allowTypes[$map[$field]['data_type']])
632 || isset($map[$field]['expression'])
633 )
634 {
635 $badField = true;
636 }
637 if ($badField)
638 {
639 unset($parameters['select'][$alias]);
640 }
641 }
642
644 // sql query build
646
647 // mandatory fields to be selected anyway
648 // alias => field
649 $fields = array(
650 'L.ID' => 'L.ID',
651 'L.CODE' => 'L.CODE',
652 'L.SORT' => 'L.SORT',
653 'LT_SORT' => 'LT.DISPLAY_SORT'
654 );
655
656 if($nameAlias === false || !preg_match('#^[a-zA-Z0-9]+$#', $nameAlias))
657 {
658 $fields['NAME'] = 'LN.NAME';
659 }
660 else
661 {
662 $fields[$nameAlias] = 'LN.NAME';
663 }
664
665 $fields = array_merge($fields, array(
666 'L.LEFT_MARGIN' => 'L.LEFT_MARGIN',
667 'L.RIGHT_MARGIN' => 'L.RIGHT_MARGIN'
668 ));
669
670 $groupFields = $fields;
671
672 // additional fields to select
673 foreach($parameters['select'] as $alias => $fld)
674 {
675 $lFld = 'L.'.$fld;
676 // check if field is already selected
677 if((string) $alias === (string) intval($alias))
678 {
679 // already selected
680 if(in_array($lFld, $fields))
681 continue;
682
683 $fields[$lFld] = $lFld;
684 //$groupFields[$lFld] = $lFld;
685 }
686 else // alias is not a number
687 {
688 if(isset($fields[$alias]))
689 continue;
690
691 $fields[$alias] = $lFld;
692 //$groupFields[$alias] = $lFld;
693 }
694
695 $groupFields[$lFld] = $lFld;
696 }
697
698 if ($doCountChildren)
699 {
700 $fields['CHILD_CNT'] = 'COUNT(LC.ID)';
701 }
702
703 // make select sql
704 $selectSql = [];
705 foreach ($fields as $alias => $fld)
706 {
707 if ($fld === $alias)
708 $selectSql[] = $fld;
709 else
710 $selectSql[] = $fld.' as '.$alias;
711 }
712
713 $selectSql = implode(', ', $selectSql);
714 //$groupSql = implode(', ', array_keys($groupFields));
715 $groupSql = implode(', ', $groupFields);
716
717 $mainSql = "select {$selectSql}
718 from {$locationTable} L
719 inner join {$locationNameTable} LN on L.ID = LN.LOCATION_ID
720 inner join {$locationTypeTable} LT on L.TYPE_ID = LT.ID ".
721
722 ($doCountChildren ? "
723 left join {$locationTable} LC on L.ID = LC.PARENT_ID
724 " : "")."
725
726 %SITE_FILTER_CONDITION%
727
728 where
729
730 %MAIN_FILTER_CONDITION%
731
732 %GROUP_BY%
733 ";
734
735 $where = array();
736
737 $where[] = "LN.LANGUAGE_ID = '" . $filterLang . "'";
738
739 if ($doFilterByCountry)
740 {
741 $where[] = "L.COUNTRY_ID = " . $filterCountryId . " ";
742 }
743
744 if ($doFilterByParent)
745 {
746 $where[] = "L.PARENT_ID = " . $filterParentId . " ";
747 }
748
749 if ($doFilterById)
750 {
751 if(is_array($filterId))
752 {
753 foreach($filterId as $idx => $id)
754 {
755 $filterId[$idx] = (int)$id;
756 }
757
758 $where[] = "L.ID IN (".implode(',', $filterId).")";
759 }
760 else
761 {
762 $where[] = "L.ID = ".$filterId;
763 }
764 }
765
766 if($doFilterByCode)
767 {
768 $where[] = "L.CODE = '".$filterCode."'";
769 }
770
771 if($doFilterByType)
772 {
773 $where[] = "L.TYPE_ID = '" . $filterTypeId . "'";
774 }
775
776 if($doFilterByName)
777 {
778 $where[] = "LN.NAME_UPPER like '" . $filterName . "%'";
779 }
780
781 $mainSql = str_replace('%MAIN_FILTER_CONDITION%', implode(' and ', $where), $mainSql);
782 $needDistinct = false;
783 $unionized = false;
784 $artificialNav = false;
785
786 if(!$doFilterBySite)
787 {
788 $sql = str_replace('%SITE_FILTER_CONDITION%', '', $mainSql);
789 }
790 else
791 {
792 $sql = array();
793 if($hasLocLinks)
794 {
795 $sql[] = str_replace('%SITE_FILTER_CONDITION%', "
796
797 inner join {$locationTable} L2 on L2.LEFT_MARGIN <= L.LEFT_MARGIN and L2.RIGHT_MARGIN >= L.RIGHT_MARGIN
798 inner join {$locationSiteTable} LS2 on L2.ID = LS2.LOCATION_ID and LS2.LOCATION_TYPE = 'L' and LS2.SITE_ID = '{$filterSite}'
799
800 ", $mainSql);
801 }
802 if($hasGrpLinks)
803 {
804 $sql[] = str_replace('%SITE_FILTER_CONDITION%', "
805
806 inner join {$locationTable} L2 on L2.LEFT_MARGIN <= L.LEFT_MARGIN and L2.RIGHT_MARGIN >= L.RIGHT_MARGIN
807 inner join {$locationGroupTable} LG on LG.LOCATION_ID = L2.ID
808 inner join {$locationSiteTable} LS2 on LG.LOCATION_GROUP_ID = LS2.LOCATION_ID and LS2.LOCATION_TYPE = 'G' and LS2.SITE_ID = '{$filterSite}'
809
810 ", $mainSql);
811
812 $useDistinct = true;
813 }
814
815 $cnt = count($sql);
816
817 if($cnt == 1)
818 {
819 $needDistinct = true;
820 }
821 else
822 {
823 // UNION removes duplicates, so distinct is required only when no union here
824 $unionized = true;
825 }
826
827 $sql = ($cnt > 1 ? '(' : '').implode(') union (', $sql).($cnt > 1 ? ')' : '');
828 }
829
830 // set groupping if needed
831 $sql = str_replace('%GROUP_BY%', $needDistinct || $doCountChildren ? "group by {$groupSql}" : '', $sql);
832
833 $parameters['order'] ??= null;
834 if (!is_array($parameters['order']))
835 {
836 $sql .= " order by 3, 4 asc, 5";
837 }
838 else
839 {
840 // currenly spike
841 if (isset($parameters['order']['NAME.NAME']))
842 {
843 $sql .= " order by 5 " . ($parameters['order']['NAME.NAME'] == 'asc' ? 'asc' : 'desc');
844 }
845 }
846
847 $offset = (int)($parameters['offset'] ?? 0);
848 $limit = (int)($parameters['limit'] ?? 0);
849
850 if ($limit)
851 {
852 if ($dbConnection->getType() == 'mssql')
853 {
854 // due to huge amount of limitations of windowed functions in transact, using artificial nav here
855 // (does not support UNION and integer indices in ORDER BY)
856 $artificialNav = true;
857 }
858 else
859 {
860 $sql = $dbHelper->getTopSql($sql, $limit, $offset);
861 }
862 }
863
864 $res = $dbConnection->query($sql);
865
866 if ($artificialNav)
867 {
868 $result = array();
869 $i = -1;
870 while($item = $res->fetch())
871 {
872 $i++;
873
874 if($i < $offset)
875 continue;
876
877 if($i >= $offset + $limit)
878 break;
879
880 $result[] = $item;
881 }
882
883 return new DB\ArrayResult($result);
884 }
885 else
886 {
887 return $res;
888 }
889 }
890}
static loadMessages($file)
Definition loc.php:64
static checkLinkUsageAny($entityPrimary)
static findNoIndex($parameters)
Definition finder.php:490
static setIndexedTypes($types=array())
Definition finder.php:69
static setIndexedLanguages($langs=array())
Definition finder.php:112
static find( $parameters, $behaviour=['FALLBACK_TO_NOINDEX_ON_NOTFOUND'=> true, 'USE_INDEX'=> true, 'USE_ORM'=> true])
Definition finder.php:162
static findUsingIndex($parameters)
Definition finder.php:294