Passed
Push — master ( 3ce2af...702ea2 )
by Timo
24:17
created

QueryBuilder::useRawQueryString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Domain\Search\Query;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2017 <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 3 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\BigramPhraseFields;
28
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Elevation;
29
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Faceting;
30
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\FieldCollapsing;
31
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Filters;
32
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Grouping;
33
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Highlighting;
34
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Operator;
35
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\PhraseFields;
36
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\QueryFields;
37
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\ReturnFields;
38
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Slops;
39
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Spellchecking;
40
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\TrigramPhraseFields;
41
use ApacheSolrForTypo3\Solr\Domain\Site\SiteHashService;
42
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
43
use ApacheSolrForTypo3\Solr\FieldProcessor\PageUidToHierarchy;
44
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
45
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
46
use ApacheSolrForTypo3\Solr\Util;
47
use TYPO3\CMS\Core\Utility\GeneralUtility;
48
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
49
50
/**
51
 * The QueryBuilder is responsible to build solr queries, that are used in the extension to query the solr server.
52
 *
53
 * @package ApacheSolrForTypo3\Solr\Domain\Search\Query
54
 */
55
class QueryBuilder {
56
57
    /**
58
     * Additional filters, which will be added to the query, as well as to
59
     * suggest queries.
60
     *
61
     * @var array
62
     */
63
    protected $additionalFilters = [];
64
65
    /**
66
     * @var TypoScriptConfiguration
67
     */
68
    protected $typoScriptConfiguration = null;
69
70
    /**
71
     * @var SolrLogManager;
72
     */
73
    protected $logger = null;
74
75
    /**
76
     * @var SiteHashService
77
     */
78
    protected $siteHashService = null;
79
80
    /**
81
     * @var Query
82
     */
83
    protected $queryToBuild = null;
84
85
    /**
86
     * QueryBuilder constructor.
87
     * @param TypoScriptConfiguration|null $configuration
88
     * @param SolrLogManager|null $solrLogManager
89
     * @param SiteHashService|null $siteHashService
90
     */
91 171
    public function __construct(TypoScriptConfiguration $configuration = null, SolrLogManager $solrLogManager = null, SiteHashService $siteHashService = null)
92
    {
93 171
        $this->typoScriptConfiguration = $configuration ?? Util::getSolrConfiguration();
94 171
        $this->logger = $solrLogManager ?? GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
95 171
        $this->siteHashService = $siteHashService ?? GeneralUtility::makeInstance(SiteHashService::class);
96 171
    }
97
98
    /**
99
     * @param Query $query
100
     * @return QueryBuilder
101
     */
102 59
    public function startFrom(Query $query): QueryBuilder
103
    {
104 59
        $this->queryToBuild = $query;
105 59
        return $this;
106
    }
107
108
    /**
109
     * @param string $queryString
110
     * @return QueryBuilder
111
     */
112 142
    public function newSearchQuery($queryString): QueryBuilder
113
    {
114 142
        $this->queryToBuild = $this->getQueryInstance($queryString);
115 142
        return $this;
116
    }
117
118
    /**
119
     * @param string $queryString
120
     * @return QueryBuilder
121
     */
122 2
    public function newSuggestQuery($queryString): QueryBuilder
123
    {
124 2
        $this->queryToBuild = $this->getSuggestQueryInstance($queryString);
125 2
        return $this;
126
    }
127
128
    /**
129
     * @return Query
130
     */
131 155
    public function getQuery(): Query
132
    {
133 155
        return $this->queryToBuild;
134
    }
135
136
    /**
137
     * Initializes the Query object and SearchComponents and returns
138
     * the initialized query object, when a search should be executed.
139
     *
140
     * @param string|null $rawQuery
141
     * @param int $resultsPerPage
142
     * @param array $additionalFiltersFromRequest
143
     * @return Query
144
     */
145 141
    public function buildSearchQuery($rawQuery, $resultsPerPage = 10, array $additionalFiltersFromRequest = []) : Query
146
    {
147 141
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
148
            $this->logger->log(SolrLogManager::INFO, 'Received search query', [$rawQuery]);
149
        }
150
        /* @var $query Query */
151 141
        return $this->newSearchQuery($rawQuery)
152 141
                ->useResultsPerPage($resultsPerPage)
153 141
                ->useReturnFieldsFromTypoScript()
154 141
                ->useQueryFieldsFromTypoScript()
155 141
                ->useInitialQueryFromTypoScript()
156 141
                ->useFiltersFromTypoScript()
157 141
                ->useFilterArray($this->getQuery()->getFilters()->addMultiple($additionalFiltersFromRequest)->getValues())
158 141
                ->useFacetingFromTypoScript()
159 141
                ->useVariantsFromTypoScript()
160 141
                ->useGroupingFromTypoScript()
161 141
                ->useHighlightingFromTypoScript()
162 141
                ->usePhraseFieldsFromTypoScript()
163 141
                ->useBigramPhraseFieldsFromTypoScript()
164 141
                ->useTrigramPhraseFieldsFromTypoScript()
165 141
                ->getQuery();
166
    }
167
168
    /**
169
     * Builds a SuggestQuery with all applied filters.
170
     *
171
     * @param string $queryString
172
     * @param array $additionalFilters
173
     * @param integer $requestedPageId
174
     * @param string $groupList
175
     * @return SuggestQuery
176
     */
177 2
    public function buildSuggestQuery(string $queryString, array $additionalFilters, int $requestedPageId, string $groupList) : SuggestQuery
178
    {
179 2
        $this->newSuggestQuery($queryString)
180 2
            ->useFiltersFromTypoScript()
181 2
            ->useSiteHashFromTypoScript($requestedPageId)
182 2
            ->useUserAccessGroups(explode(',', $groupList));
183
184 2
        $this->queryToBuild->setOmitHeader();
185
186 2
        if (!empty($additionalFilters)) {
187
            $this->useFilterArray($additionalFilters);
188
        }
189
190 2
        return $this->queryToBuild;
191
    }
192
193
    /**
194
     * Uses an array of filters and applies them to the query.
195
     *
196
     * @param array $filterArray
197
     * @return QueryBuilder
198
     */
199 143
    public function useFilterArray(array $filterArray): QueryBuilder
200
    {
201 143
        foreach ($filterArray as $key => $additionalFilter) {
202 4
            $this->useFilter($additionalFilter, $key);
203
        }
204
205 143
        return $this;
206
    }
207
208
    /**
209
     * Returns Query for Search which finds document for given page.
210
     * Note: The Connection is per language as recommended in ext-solr docs.
211
     *
212
     * @return Query
213
     */
214 1
    public function buildPageQuery($pageId)
215
    {
216 1
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
217 1
        $site = $siteRepository->getSiteByPageId($pageId);
218
219 1
        return $this->newSearchQuery('')
220 1
            ->useQueryString('*:*')
221 1
            ->useFilter('(type:pages AND uid:' . $pageId . ') OR (*:* AND pid:' . $pageId . ' NOT type:pages)', 'type')
222 1
            ->useFilter('siteHash:' . $site->getSiteHash(), 'siteHash')
223 1
            ->useReturnFields(ReturnFields::fromString('*'))
224 1
            ->useSorting('type asc, title asc')
225 1
            ->useQueryType('standard')
226 1
            ->useRawQueryString()
227 1
            ->getQuery();
228
    }
229
230
    /**
231
     * Returns a query for single record
232
     *
233
     * @return Query
234
     */
235
    public function buildRecordQuery($type, $uid, $pageId): Query
236
    {
237
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
238
        $site = $siteRepository->getSiteByPageId($pageId);
239
240
        return $this->newSearchQuery('')
241
            ->useQueryString('*:*')
242
            ->useFilter('type:' . $type . ' AND uid:' . $uid, 'type')
243
            ->useFilter('siteHash:' . $site->getSiteHash(), 'siteHash')
244
            ->useReturnFields(ReturnFields::fromString('*'))
245
            ->useSorting('type asc, title asc')
246
            ->useQueryType('standard')
247
            ->useRawQueryString()
248
            ->getQuery();
249
    }
250
251
    /**
252
     * Applies the queryString that is used to search
253
     *
254
     * @param string $queryString
255
     * @return QueryBuilder
256
     */
257 1
    public function useQueryString($queryString): QueryBuilder
258
    {
259 1
        $this->queryToBuild->getQueryStringContainer()->setQueryString($queryString);
260 1
        return $this;
261
    }
262
263
    /**
264
     * Applies the useRawQueryString flag to the queryString.
265
     *
266
     * @param boolean $boolean
267
     * @return QueryBuilder
268
     */
269 1
    public function useRawQueryString($boolean = true): QueryBuilder
270
    {
271 1
        $this->queryToBuild->getQueryStringContainer()->useRawQueryString($boolean);
272 1
        return $this;
273
    }
274
275
    /**
276
     * Applies the passed queryType to the query.
277
     *
278
     * @param string $queryType
279
     * @return QueryBuilder
280
     */
281 1
    public function useQueryType($queryType): QueryBuilder
282
    {
283 1
        $this->queryToBuild->setQueryType($queryType);
284 1
        return $this;
285
    }
286
287
    /**
288
     * Applies the passed sorting to the query.
289
     *
290
     * @param string $sorting
291
     * @return QueryBuilder
292
     */
293 1
    public function useSorting($sorting): QueryBuilder
294
    {
295 1
        $this->queryToBuild->setSorting($sorting);
296 1
        return $this;
297
    }
298
299
    /**
300
     * @param int $resultsPerPage
301
     * @return QueryBuilder
302
     */
303 141
    public function useResultsPerPage($resultsPerPage): QueryBuilder
304
    {
305 141
        $this->queryToBuild->getPagination()->setResultsPerPage($resultsPerPage);
306 141
        return $this;
307
    }
308
309
    /**
310
     * @param int $page
311
     * @return QueryBuilder
312
     */
313
    public function usePage($page): QueryBuilder
314
    {
315
        $this->queryToBuild->getPagination()->setPage($page);
316
        return $this;
317
    }
318
319
    /**
320
     * @param Operator $operator
321
     * @return QueryBuilder
322
     */
323
    public function useOperator(Operator $operator): QueryBuilder
324
    {
325
        $this->queryToBuild->setOperator($operator);
326
        return $this;
327
    }
328
329
    /**
330
     * @return QueryBuilder
331
     */
332 50
    public function useSlopsFromTypoScript(): QueryBuilder
333
    {
334 50
        return $this->useSlops(Slops::fromTypoScriptConfiguration($this->typoScriptConfiguration));
335
    }
336
337
    /**
338
     * @param Slops $slops
339
     * @return QueryBuilder
340
     */
341 50
    public function useSlops(Slops $slops): QueryBuilder
342
    {
343 50
        $this->queryToBuild->setSlops($slops);
344 50
        return $this;
345
    }
346
347
    /**
348
     * Uses the configured boost queries from typoscript
349
     *
350
     * @return QueryBuilder
351
     */
352 50
    public function useBoostQueriesFromTypoScript(): QueryBuilder
353
    {
354 50
        $searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
355
356 50
        if (!empty($searchConfiguration['query.']['boostQuery'])) {
357 1
            return $this->useBoostQueries($searchConfiguration['query.']['boostQuery']);
358
        }
359
360 49
        if (!empty($searchConfiguration['query.']['boostQuery.'])) {
361 1
            $boostQueries = $searchConfiguration['query.']['boostQuery.'];
362 1
            return $this->useBoostQueries(array_values($boostQueries));
363
        }
364
365 48
        return $this;
366
    }
367
368
    /**
369
     * Uses the passed boostQuer(y|ies) for the query.
370
     *
371
     * @param string|array $boostQueries
372
     * @return QueryBuilder
373
     */
374 2
    public function useBoostQueries($boostQueries): QueryBuilder
375
    {
376 2
        $this->queryToBuild->setBoostQuery($boostQueries);
377 2
        return $this;
378
    }
379
380
    /**
381
     * Uses the configured boostFunction from the typoscript configuration.
382
     *
383
     * @return QueryBuilder
384
     */
385 50
    public function useBoostFunctionFromTypoScript(): QueryBuilder
386
    {
387 50
        $searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
388 50
        if (!empty($searchConfiguration['query.']['boostFunction'])) {
389 1
            return $this->useBoostFunction($searchConfiguration['query.']['boostFunction']);
390
        }
391
392 49
        return $this;
393
    }
394
395
    /**
396
     * Uses the passed boostFunction for the query.
397
     *
398
     * @param string $boostFunction
399
     * @return QueryBuilder
400
     */
401 1
    public function useBoostFunction($boostFunction): QueryBuilder
402
    {
403 1
        $this->queryToBuild->setBoostFunction($boostFunction);
404 1
        return $this;
405
    }
406
407
    /**
408
     * Uses the configured minimumMatch from the typoscript configuration.
409
     *
410
     * @return QueryBuilder
411
     */
412 50
    public function useMinimumMatchFromTypoScript(): QueryBuilder
413
    {
414 50
        $searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
415 50
        if (!empty($searchConfiguration['query.']['minimumMatch'])) {
416 1
            return $this->useMinimumMatch($searchConfiguration['query.']['minimumMatch']);
417
        }
418
419 49
        return $this;
420
    }
421
422
    /**
423
     * Uses the passed minimumMatch(mm) for the query.
424
     *
425
     * @param string $boostFunction
426
     * @return QueryBuilder
427
     */
428 1
    public function useMinimumMatch($boostFunction): QueryBuilder
429
    {
430 1
        $this->queryToBuild->setMinimumMatch($boostFunction);
431 1
        return $this;
432
    }
433
434
    /**
435
     * @return QueryBuilder
436
     */
437 50
    public function useTieParameterFromTypoScript(): QueryBuilder
438
    {
439 50
        $searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
440 50
        if (empty($searchConfiguration['query.']['tieParameter'])) {
441 49
            return $this;
442
        }
443
444 1
        return $this->useTieParameter($searchConfiguration['query.']['tieParameter']);
445
    }
446
447
    /**
448
     * Applies the tie parameter to the query.
449
     *
450
     * @param mixed $tie
451
     * @return QueryBuilder
452
     */
453 1
    public function useTieParameter($tie): QueryBuilder
454
    {
455 1
        $this->queryToBuild->setTieParameter($tie);
456 1
        return $this;
457
    }
458
459
    /**
460
     * Applies the configured query fields from the typoscript configuration.
461
     *
462
     * @return QueryBuilder
463
     */
464 141
    public function useQueryFieldsFromTypoScript(): QueryBuilder
465
    {
466 141
        return $this->useQueryFields(QueryFields::fromString($this->typoScriptConfiguration->getSearchQueryQueryFields()));
467
    }
468
469
    /**
470
     * Applies custom QueryFields to the query.
471
     *
472
     * @param QueryFields $queryFields
473
     * @return QueryBuilder
474
     */
475 141
    public function useQueryFields(QueryFields $queryFields): QueryBuilder
476
    {
477 141
        $this->queryToBuild->setQueryFields($queryFields);
478 141
        return $this;
479
    }
480
481
    /**
482
     * Applies the configured return fields from the typoscript configuration.
483
     *
484
     * @return QueryBuilder
485
     */
486 141
    public function useReturnFieldsFromTypoScript(): QueryBuilder
487
    {
488 141
        $returnFieldsArray = (array)$this->typoScriptConfiguration->getSearchQueryReturnFieldsAsArray(['*', 'score']);
489 141
        return $this->useReturnFields(ReturnFields::fromArray($returnFieldsArray));
490
    }
491
492
    /**
493
     * Applies custom ReturnFields to the query.
494
     *
495
     * @param ReturnFields $returnFields
496
     * @return QueryBuilder
497
     */
498 142
    public function useReturnFields(ReturnFields $returnFields): QueryBuilder
499
    {
500 142
        $this->queryToBuild->setReturnFields($returnFields);
501 142
        return $this;
502
    }
503
504
    /**
505
     * Can be used to apply the allowed sites from plugin.tx_solr.search.query.allowedSites to the query.
506
     *
507
     * @param int $requestedPageId
508
     * @return QueryBuilder
509
     */
510 39
    public function useSiteHashFromTypoScript(int $requestedPageId): QueryBuilder
511
    {
512 39
        $queryConfiguration = $this->typoScriptConfiguration->getObjectByPathOrDefault('plugin.tx_solr.search.query.', []);
513 39
        $allowedSites = $this->siteHashService->getAllowedSitesForPageIdAndAllowedSitesConfiguration($requestedPageId, $queryConfiguration['allowedSites']);
514 39
        return $this->useSiteHashFromAllowedSites($allowedSites);
515
    }
516
517
    /**
518
     * Can be used to apply a list of allowed sites to the query.
519
     *
520
     * @param string $allowedSites
521
     * @return QueryBuilder
522
     */
523 39
    public function useSiteHashFromAllowedSites($allowedSites): QueryBuilder
524
    {
525 39
        $isAnySiteAllowed = trim($allowedSites) === '*';
526 39
        if ($isAnySiteAllowed) {
527
            // no filter required
528 1
            return $this;
529
        }
530
531 38
        $allowedSites = GeneralUtility::trimExplode(',', $allowedSites);
532 38
        $filters = [];
533 38
        foreach ($allowedSites as $site) {
534 38
            $siteHash = $this->siteHashService->getSiteHashForDomain($site);
535 38
            $filters[] = 'siteHash:"' . $siteHash . '"';
536
        }
537
538 38
        $siteHashFilterString = implode(' OR ', $filters);
539 38
        return $this->useFilter($siteHashFilterString, 'siteHash');
540
    }
541
542
    /**
543
     * Can be used to use a specific filter string in the solr query.
544
     *
545
     * @param string $filterString
546
     * @param string $filterName
547
     * @return QueryBuilder
548
     */
549 47
    public function useFilter($filterString, $filterName = ''): QueryBuilder
550
    {
551 47
        $this->queryToBuild->getFilters()->add($filterString, $filterName);
552 47
        return $this;
553
    }
554
555
    /**
556
     * Can be used to filter the result on an applied list of user groups.
557
     *
558
     * @param array $groups
559
     * @return QueryBuilder
560
     */
561 43
    public function useUserAccessGroups(array $groups): QueryBuilder
562
    {
563 43
        $groups = array_map('intval', $groups);
564 43
        $groups[] = 0; // always grant access to public documents
565 43
        $groups = array_unique($groups);
566 43
        sort($groups, SORT_NUMERIC);
567
568 43
        $accessFilter = '{!typo3access}' . implode(',', $groups);
569 43
        return $this->useFilter($accessFilter, 'accessFilter');
570
    }
571
572
    /**
573
     * Applies the configured initial query settings to set the alternative query for solr as required.
574
     *
575
     * @return QueryBuilder
576
     */
577 141
    public function useInitialQueryFromTypoScript(): QueryBuilder
578
    {
579 141
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
580
            // empty main query, but using a "return everything"
581
            // alternative query in q.alt
582 38
            $this->queryToBuild->setAlternativeQuery('*:*');
583
        }
584
585 141
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
586 4
            $this->queryToBuild->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
587
        }
588
589 141
        return $this;
590
    }
591
592
    /**
593
     * Applies the configured facets from the typoscript configuration on the query.
594
     *
595
     * @return QueryBuilder
596
     */
597 141
    public function useFacetingFromTypoScript(): QueryBuilder
598
    {
599 141
        return $this->useFaceting(Faceting::fromTypoScriptConfiguration($this->typoScriptConfiguration));
600
    }
601
602
    /**
603
     * Applies a custom Faceting configuration to the query.
604
     *
605
     * @param Faceting $faceting
606
     * @return QueryBuilder
607
     */
608 141
    public function useFaceting(Faceting $faceting): QueryBuilder
609
    {
610 141
        $this->queryToBuild->setFaceting($faceting);
611 141
        return $this;
612
    }
613
614
    /**
615
     * Applies the configured variants from the typoscript configuration on the query.
616
     *
617
     * @return QueryBuilder
618
     */
619 141
    public function useVariantsFromTypoScript(): QueryBuilder
620
    {
621 141
        return $this->useFieldCollapsing(FieldCollapsing::fromTypoScriptConfiguration($this->typoScriptConfiguration));
622
    }
623
624
    /**
625
     * @param FieldCollapsing $fieldCollapsing
626
     * @return QueryBuilder
627
     */
628 141
    public function useFieldCollapsing(FieldCollapsing $fieldCollapsing): QueryBuilder
629
    {
630 141
        $this->queryToBuild->setFieldCollapsing($fieldCollapsing);
631 141
        return $this;
632
    }
633
634
    /**
635
     * Applies the configured groupings from the typoscript configuration to the query.
636
     *
637
     * @return QueryBuilder
638
     */
639 141
    public function useGroupingFromTypoScript(): QueryBuilder
640
    {
641 141
        return $this->useGrouping(Grouping::fromTypoScriptConfiguration($this->typoScriptConfiguration));
642
    }
643
644
    /**
645
     * Applies a custom initialized grouping to the query.
646
     *
647
     * @param Grouping $grouping
648
     * @return QueryBuilder
649
     */
650 141
    public function useGrouping(Grouping $grouping): QueryBuilder
651
    {
652 141
        $this->queryToBuild->setGrouping($grouping);
653 141
        return $this;
654
    }
655
656
    /**
657
     * Applies the configured highlighting from the typoscript configuration to the query.
658
     *
659
     * @return QueryBuilder
660
     */
661 141
    public function useHighlightingFromTypoScript(): QueryBuilder
662
    {
663 141
        return $this->useHighlighting(Highlighting::fromTypoScriptConfiguration($this->typoScriptConfiguration));
664
    }
665
666
    /**
667
     * @param Highlighting $highlighting
668
     * @return QueryBuilder
669
     */
670 141
    public function useHighlighting(Highlighting $highlighting): QueryBuilder
671
    {
672 141
        $this->queryToBuild->setHighlighting($highlighting);
673 141
        return $this;
674
    }
675
676
    /**
677
     * Applies the configured filters (page section and other from typoscript).
678
     *
679
     * @return QueryBuilder
680
     */
681 143
    public function useFiltersFromTypoScript(): QueryBuilder
682
    {
683 143
        $filters = Filters::fromTypoScriptConfiguration($this->typoScriptConfiguration);
684 143
        $this->queryToBuild->setFilters($filters);
685
686 143
        $this->useFilterArray($this->getAdditionalFilters());
687
688 143
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
689
690 143
        if (!is_array($searchQueryFilters) || count($searchQueryFilters) <= 0) {
0 ignored issues
show
introduced by
The condition is_array($searchQueryFilters) is always true.
Loading history...
691 139
            return $this;
692
        }
693
694
        // special filter to limit search to specific page tree branches
695 4
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
696 1
            $pageIds = GeneralUtility::trimExplode(',', $searchQueryFilters['__pageSections']);
697 1
            $this->usePageSectionsFromPageIds($pageIds);
698 1
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
699
        }
700
701 4
        return $this;
702
    }
703
704
    /**
705
     * Applies the configured elevation from the typoscript configuration.
706
     *
707
     * @return QueryBuilder
708
     */
709 37
    public function useElevationFromTypoScript(): QueryBuilder
710
    {
711 37
        return $this->useElevation(Elevation::fromTypoScriptConfiguration($this->typoScriptConfiguration));
712
    }
713
714
    /**
715
     * @param Elevation $elevation
716
     * @return QueryBuilder
717
     */
718 37
    public function useElevation(Elevation $elevation): QueryBuilder
719
    {
720 37
        $this->queryToBuild->setElevation($elevation);
721 37
        return $this;
722
    }
723
724
    /**
725
     * Applies the configured spellchecking from the typoscript configuration.
726
     *
727
     * @return QueryBuilder
728
     */
729 33
    public function useSpellcheckingFromTypoScript(): QueryBuilder
730
    {
731 33
        return $this->useSpellchecking(Spellchecking::fromTypoScriptConfiguration($this->typoScriptConfiguration));
732
    }
733
734
    /**
735
     * @param Spellchecking $spellchecking
736
     * @return QueryBuilder
737
     */
738 33
    public function useSpellchecking(Spellchecking $spellchecking): QueryBuilder
739
    {
740 33
        $this->queryToBuild->setSpellchecking($spellchecking);
741 33
        return $this;
742
    }
743
744
    /**
745
     * Applies the passed pageIds as __pageSection filter.
746
     *
747
     * @param array $pageIds
748
     * @return QueryBuilder
749
     */
750 1
    public function usePageSectionsFromPageIds(array $pageIds = []): QueryBuilder
751
    {
752 1
        $filters = [];
753
754
        /** @var $processor PageUidToHierarchy */
755 1
        $processor = GeneralUtility::makeInstance(PageUidToHierarchy::class);
756 1
        $hierarchies = $processor->process($pageIds);
757
758 1
        foreach ($hierarchies as $hierarchy) {
759 1
            $lastLevel = array_pop($hierarchy);
760 1
            $filters[] = 'rootline:"' . $lastLevel . '"';
761
        }
762
763 1
        $pageSectionsFilterString = implode(' OR ', $filters);
764 1
        return $this->useFilter($pageSectionsFilterString, 'pageSections');
765
    }
766
767
    /**
768
     * Applies the configured phrase fields from the typoscript configuration to the query.
769
     *
770
     * @return QueryBuilder
771
     */
772 141
    public function usePhraseFieldsFromTypoScript(): QueryBuilder
773
    {
774 141
        return $this->usePhraseFields(PhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
0 ignored issues
show
Bug introduced by
ApacheSolrForTypo3\Solr\...ypoScriptConfiguration) of type ApacheSolrForTypo3\Solr\...lder\BigramPhraseFields is incompatible with the type ApacheSolrForTypo3\Solr\...terBuilder\PhraseFields expected by parameter $phraseFields of ApacheSolrForTypo3\Solr\...lder::usePhraseFields(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

774
        return $this->usePhraseFields(/** @scrutinizer ignore-type */ PhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
Loading history...
775
    }
776
777
    /**
778
     * Applies a custom configured PhraseFields to the query.
779
     *
780
     * @param PhraseFields $phraseFields
781
     * @return QueryBuilder
782
     */
783 141
    public function usePhraseFields(PhraseFields $phraseFields): QueryBuilder
784
    {
785 141
        $this->queryToBuild->setPhraseFields($phraseFields);
786 141
        return $this;
787
    }
788
789
    /**
790
     * Applies the configured bigram phrase fields from the typoscript configuration to the query.
791
     *
792
     * @return QueryBuilder
793
     */
794 141
    public function useBigramPhraseFieldsFromTypoScript(): QueryBuilder
795
    {
796 141
        return $this->useBigramPhraseFields(BigramPhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
797
    }
798
799
    /**
800
     * Applies a custom configured BigramPhraseFields to the query.
801
     *
802
     * @param BigramPhraseFields $bigramPhraseFields
803
     * @return QueryBuilder
804
     */
805 141
    public function useBigramPhraseFields(BigramPhraseFields $bigramPhraseFields): QueryBuilder
806
    {
807 141
        $this->queryToBuild->setBigramPhraseFields($bigramPhraseFields);
808 141
        return $this;
809
    }
810
811
    /**
812
     * Applies the configured trigram phrase fields from the typoscript configuration to the query.
813
     *
814
     * @return QueryBuilder
815
     */
816 141
    public function useTrigramPhraseFieldsFromTypoScript(): QueryBuilder
817
    {
818 141
        return $this->useTrigramPhraseFields(TrigramPhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
819
    }
820
821
    /**
822
     * Applies a custom configured TrigramPhraseFields to the query.
823
     *
824
     * @param TrigramPhraseFields $trigramPhraseFields
825
     * @return QueryBuilder
826
     */
827 141
    public function useTrigramPhraseFields(TrigramPhraseFields $trigramPhraseFields): QueryBuilder
828
    {
829 141
        $this->queryToBuild->setTrigramPhraseFields($trigramPhraseFields);
830 141
        return $this;
831
    }
832
833
    /**
834
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
835
     *
836
     * @return array
837
     */
838 148
    public function getAdditionalFilters() : array
839
    {
840
        // when we've build the additionalFilter once, we could return them
841 148
        if (count($this->additionalFilters) > 0) {
842 2
            return $this->additionalFilters;
843
        }
844
845 148
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
846 148
        if (!is_array($searchQueryFilters) || count($searchQueryFilters) <= 0) {
0 ignored issues
show
introduced by
The condition is_array($searchQueryFilters) is always true.
Loading history...
847 145
            return [];
848
        }
849
850 4
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
851
852
        // all other regular filters
853 4
        foreach ($searchQueryFilters as $filterKey => $filter) {
854
            // the __pageSections filter should not be handled as additional filter
855 4
            if ($filterKey === '__pageSections') {
856 1
                continue;
857
            }
858
859 3
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
860 3
            if ($filterIsArray) {
861
                continue;
862
            }
863
864 3
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
865 3
            if ($hasSubConfiguration) {
866
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
867
            }
868
869 3
            $this->additionalFilters[$filterKey] = $filter;
870
        }
871
872 4
        return $this->additionalFilters;
873
    }
874
875
    /**
876
     * @param string $rawQuery
877
     * @return Query|object
878
     */
879 142
    protected function getQueryInstance($rawQuery): Query
880
    {
881 142
        $query = GeneralUtility::makeInstance(Query::class, /** @scrutinizer ignore-type */ $rawQuery);
882 142
        return $query;
883
    }
884
885
886
    /**
887
     * @param string $rawQuery
888
     * @return SuggestQuery
889
     */
890 2
    protected function getSuggestQueryInstance($rawQuery): SuggestQuery
891
    {
892 2
        $query = GeneralUtility::makeInstance(SuggestQuery::class, /** @scrutinizer ignore-type */ $rawQuery, /** @scrutinizer ignore-type */ $this->typoScriptConfiguration);
893
894 2
        return $query;
895
    }
896
}