Passed
Push — master ( cc3f84...4a930e )
by Timo
23:43
created

AbstractQueryBuilder   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 503
Duplicated Lines 0 %

Test Coverage

Coverage 97.87%

Importance

Changes 0
Metric Value
wmc 50
eloc 100
dl 0
loc 503
ccs 138
cts 141
cp 0.9787
rs 8.4
c 0
b 0
f 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
A useGrouping() 0 3 1
A getQuery() 0 3 1
A removeAlternativeQuery() 0 4 1
A useAlternativeQuery() 0 4 1
A useFilterArray() 0 7 2
A useFilter() 0 5 2
A useHighlighting() 0 3 1
A useQueryFields() 0 3 1
A useFaceting() 0 3 1
A usePage() 0 4 1
A useTrigramPhraseFields() 0 3 1
A usePhraseFields() 0 3 1
A useTieParameter() 0 4 1
A removeFilterByFunction() 0 12 3
A removeFilterByFieldName() 0 7 1
A removeFilterByValue() 0 6 1
A useSortings() 0 7 2
A useOmitHeader() 0 5 1
A removeOperator() 0 4 1
A useBigramPhraseFields() 0 3 1
A useQueryType() 0 4 1
A useReturnFields() 0 3 1
A useSlops() 0 3 1
A useQueryString() 0 4 1
A removeMinimumMatch() 0 4 1
A useResultsPerPage() 0 4 1
A useSorting() 0 9 2
A removeAllBoostQueries() 0 4 1
A useBoostFunction() 0 4 1
A useMinimumMatch() 0 4 1
A removeAllBoostFunctions() 0 4 1
A useBoostQueries() 0 13 3
A useOperator() 0 4 1
A useElevation() 0 3 1
A startFrom() 0 4 1
A removeAllSortings() 0 4 1
A removeFilterByName() 0 6 1
A removeQueryType() 0 4 1
A useSpellchecking() 0 3 1
A useFieldCollapsing() 0 3 1
A useDebug() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like AbstractQueryBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractQueryBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\Domain\Search\Query;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2017 <[email protected]>
9
 *  All rights reserved
10
 *
11
 *  This script is part of the TYPO3 project. The TYPO3 project is
12
 *  free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU General Public License as published by
14
 *  the Free Software Foundation; either version 3 of the License, or
15
 *  (at your option) any later version.
16
 *
17
 *  The GNU General Public License can be found at
18
 *  http://www.gnu.org/copyleft/gpl.html.
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
28
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\BigramPhraseFields;
29
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Elevation;
30
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Faceting;
31
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\FieldCollapsing;
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\Sorting;
40
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Sortings;
41
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\Spellchecking;
42
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\TrigramPhraseFields;
43
use TYPO3\CMS\Core\Utility\GeneralUtility;
44
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
45
46
/**
47
 * The AbstractQueryBuilder contains all logic to initialize solr queries independent from TYPO3.
48
 *
49
 * @package ApacheSolrForTypo3\Solr\Domain\Search\Query
50
 */
51
abstract class AbstractQueryBuilder {
52
53
    /**
54
     * @var Query
55
     */
56
    protected $queryToBuild = null;
57
58
    /**
59
     * @param Query $query
60
     * @return $this
61
     */
62 125
    public function startFrom(Query $query)
63
    {
64 125
        $this->queryToBuild = $query;
65 125
        return $this;
66
    }
67
68
    /**
69
     * @return Query
70
     */
71 167
    public function getQuery(): Query
72
    {
73 167
        return $this->queryToBuild;
74
    }
75
76
    /**
77
     * @param bool $omitHeader
78
     * @return $this
79
     */
80 136
    public function useOmitHeader($omitHeader = true)
81
    {
82 136
        $this->queryToBuild->setOmitHeader($omitHeader);
83
84 136
        return $this;
85
    }
86
87
    /**
88
     * Uses an array of filters and applies them to the query.
89
     *
90
     * @param array $filterArray
91
     * @return $this
92
     */
93 138
    public function useFilterArray(array $filterArray)
94
    {
95 138
        foreach ($filterArray as $key => $additionalFilter) {
96 10
            $this->useFilter($additionalFilter, $key);
97
        }
98
99 138
        return $this;
100
    }
101
102
    /**
103
     * Applies the queryString that is used to search
104
     *
105
     * @param string $queryString
106
     * @return $this
107
     */
108 5
    public function useQueryString($queryString)
109
    {
110 5
        $this->queryToBuild->setQuery($queryString);
111 5
        return $this;
112
    }
113
114
    /**
115
     * Applies the passed queryType to the query.
116
     *
117
     * @param string $queryType
118
     * @return $this
119
     */
120 2
    public function useQueryType(string $queryType)
121
    {
122 2
        $this->queryToBuild->addParam('qt', $queryType);
123 2
        return $this;
124
    }
125
126
    /**
127
     * Remove the queryType (qt) from the query.
128
     *
129
     * @return $this
130
     */
131 1
    public function removeQueryType()
132
    {
133 1
        $this->queryToBuild->addParam('qt', null);
134 1
        return $this;
135
    }
136
137
    /**
138
     * Can be used to remove all sortings from the query.
139
     *
140
     * @return $this
141
     */
142 1
    public function removeAllSortings()
143
    {
144 1
        $this->queryToBuild->clearSorts();
145 1
        return $this;
146
    }
147
148
    /**
149
     * Applies the passed sorting to the query.
150
     *
151
     * @param Sorting $sorting
152
     * @return $this
153
     */
154 7
    public function useSorting(Sorting $sorting)
155
    {
156 7
        if (strpos($sorting->getFieldName(), 'relevance') !== false) {
157 1
            $this->removeAllSortings();
158 1
            return $this;
159
        }
160
161 7
        $this->queryToBuild->addSort($sorting->getFieldName(), $sorting->getDirection());
162 7
        return $this;
163
    }
164
165
    /**
166
     * Applies the passed sorting to the query.
167
     *
168
     * @param Sortings $sortings
169
     * @return $this
170
     */
171 6
    public function useSortings(Sortings $sortings)
172
    {
173 6
        foreach($sortings->getSortings() as $sorting) {
174 6
            $this->useSorting($sorting);
175
        }
176
177 6
        return $this;
178
    }
179
180
    /**
181
     * @param int $resultsPerPage
182
     * @return $this
183
     */
184 136
    public function useResultsPerPage($resultsPerPage)
185
    {
186 136
        $this->queryToBuild->setRows($resultsPerPage);
187 136
        return $this;
188
    }
189
190
    /**
191
     * @param int $page
192
     * @return $this
193
     */
194
    public function usePage($page)
195
    {
196
        $this->queryToBuild->setStart($page);
197
        return $this;
198
    }
199
200
    /**
201
     * @param Operator $operator
202
     * @return $this
203
     */
204 1
    public function useOperator(Operator $operator)
205
    {
206 1
        $this->queryToBuild->setQueryDefaultOperator( $operator->getOperator());
207 1
        return $this;
208
    }
209
210
    /**
211
     * Remove the default query operator.
212
     *
213
     * @return $this
214
     */
215 1
    public function removeOperator()
216
    {
217 1
        $this->queryToBuild->setQueryDefaultOperator(null);
218 1
        return $this;
219
    }
220
221
    /**
222
     * @param Slops $slops
223
     * @return $this
224
     */
225 55
    public function useSlops(Slops $slops)
226
    {
227 55
        return $slops->build($this);
228
    }
229
230
    /**
231
     * Uses the passed boostQuer(y|ies) for the query.
232
     *
233
     * @param string|array $boostQueries
234
     * @return $this
235
     */
236 3
    public function useBoostQueries($boostQueries)
237
    {
238 3
        $boostQueryArray = [];
239 3
        if(is_array($boostQueries)) {
240 1
            foreach($boostQueries as $boostQuery) {
241 1
                $boostQueryArray[] = ['key' => md5($boostQuery), 'query' => $boostQuery];
242
            }
243
        } else {
244 2
            $boostQueryArray[] = ['key' => md5($boostQueries), 'query' => $boostQueries];
245
        }
246
247 3
        $this->queryToBuild->getEDisMax()->setBoostQueries($boostQueryArray);
248 3
        return $this;
249
    }
250
251
    /**
252
     * Removes all boost queries from the query.
253
     *
254
     * @return $this
255
     */
256 1
    public function removeAllBoostQueries()
257
    {
258 1
        $this->queryToBuild->getEDisMax()->clearBoostQueries();
259 1
        return $this;
260
    }
261
262
    /**
263
     * Uses the passed boostFunction for the query.
264
     *
265
     * @param string $boostFunction
266
     * @return $this
267
     */
268 2
    public function useBoostFunction(string $boostFunction)
269
    {
270 2
        $this->queryToBuild->getEDisMax()->setBoostFunctions($boostFunction);
271 2
        return $this;
272
    }
273
274
    /**
275
     * Removes all previously configured boost functions.
276
     *
277
     * @return $this
278
     */
279 1
    public function removeAllBoostFunctions()
280
    {
281 1
        $this->queryToBuild->getEDisMax()->setBoostFunctions(null);
282 1
        return $this;
283
    }
284
285
286
    /**
287
     * Uses the passed minimumMatch(mm) for the query.
288
     *
289
     * @param string $minimumMatch
290
     * @return $this
291
     */
292 2
    public function useMinimumMatch(string $minimumMatch)
293
    {
294 2
        $this->queryToBuild->getEDisMax()->setMinimumMatch($minimumMatch);
295 2
        return $this;
296
    }
297
298
    /**
299
     * Remove any previous passed minimumMatch parameter.
300
     *
301
     * @return $this
302
     */
303 1
    public function removeMinimumMatch()
304
    {
305 1
        $this->queryToBuild->getEDisMax()->setMinimumMatch(null);
306 1
        return $this;
307
    }
308
309
310
    /**
311
     * Applies the tie parameter to the query.
312
     *
313
     * @param mixed $tie
314
     * @return $this
315
     */
316 1
    public function useTieParameter($tie)
317
    {
318 1
        $this->queryToBuild->getEDisMax()->setTie($tie);
319 1
        return $this;
320
    }
321
322
    /**
323
     * Applies custom QueryFields to the query.
324
     *
325
     * @param QueryFields $queryFields
326
     * @return $this
327
     */
328 144
    public function useQueryFields(QueryFields $queryFields)
329
    {
330 144
        return $queryFields->build($this);
331
    }
332
333
    /**
334
     * Applies custom ReturnFields to the query.
335
     *
336
     * @param ReturnFields $returnFields
337
     * @return $this
338
     */
339 138
    public function useReturnFields(ReturnFields $returnFields)
340
    {
341 138
        return $returnFields->build($this);
342
    }
343
344
    /**
345
     * Can be used to use a specific filter string in the solr query.
346
     *
347
     * @param string $filterString
348
     * @param string $filterName
349
     * @return $this
350
     */
351 58
    public function useFilter($filterString, $filterName = '')
352
    {
353 58
        $filterName = $filterName === '' ? $filterString : $filterName;
354 58
        $this->queryToBuild->addFilterQuery(['key' => $filterName, 'query' => $filterString]);
355 58
        return $this;
356
    }
357
358
    /**
359
     * Removes a filter by the fieldName.
360
     *
361
     * @param string $fieldName
362
     * @return $this
363
     */
364 1
    public function removeFilterByFieldName($fieldName)
365
    {
366 1
        return $this->removeFilterByFunction(
367 1
            function($key, $query) use ($fieldName) {
368 1
                $queryString = $query->getQuery();
369 1
                $storedFieldName = substr($queryString,0, strpos($queryString, ":"));
370 1
                return $storedFieldName == $fieldName;
371 1
            }
372
        );
373
    }
374
375
    /**
376
     * Removes a filter by the name of the filter (also known as key).
377
     *
378
     * @param string $name
379
     * @return $this
380
     */
381 1
    public function removeFilterByName($name)
382
    {
383 1
        return $this->removeFilterByFunction(
384 1
            function($key, $query) use ($name) {
385 1
                $key = $query->getKey();
386 1
                return $key == $name;
387 1
            }
388
        );
389
    }
390
391
    /**
392
     * Removes a filter by the filter value.
393
     *
394
     * @param string $value
395
     * @return $this
396
     */
397 1
    public function removeFilterByValue($value)
398
    {
399 1
        return $this->removeFilterByFunction(
400 1
            function($key, $query) use ($value) {
401 1
                $query = $query->getQuery();
402 1
                return $query == $value;
403 1
            }
404
        );
405
    }
406
407
    /**
408
     * @param \Closure $filterFunction
409
     * @return $this
410
     */
411 2
    public function removeFilterByFunction($filterFunction)
412
    {
413 2
        $queries = $this->queryToBuild->getFilterQueries();
414 2
        foreach($queries as $key =>  $query) {
415 2
            $canBeRemoved = $filterFunction($key, $query);
416 2
            if($canBeRemoved) {
417 2
                unset($queries[$key]);
418
            }
419
        }
420
421 2
        $this->queryToBuild->setFilterQueries($queries);
422 2
        return $this;
423
    }
424
425
    /**
426
     * Passes the alternative query to the Query
427
     * @param string $query
428
     * @return $this
429
     */
430 41
    public function useAlternativeQuery(string $query)
431
    {
432 41
        $this->queryToBuild->getEDisMax()->setQueryAlternative($query);
433 41
        return $this;
434
    }
435
436
    /**
437
     * Remove the alternative query from the Query.
438
     *
439
     * @return $this
440
     */
441 1
    public function removeAlternativeQuery()
442
    {
443 1
        $this->queryToBuild->getEDisMax()->setQueryAlternative(null);
444 1
        return $this;
445
    }
446
447
    /**
448
     * Applies a custom Faceting configuration to the query.
449
     *
450
     * @param Faceting $faceting
451
     * @return $this
452
     */
453 137
    public function useFaceting(Faceting $faceting)
454
    {
455 137
        return $faceting->build($this);
456
    }
457
458
    /**
459
     * @param FieldCollapsing $fieldCollapsing
460
     * @return $this
461
     */
462 137
    public function useFieldCollapsing(FieldCollapsing $fieldCollapsing)
463
    {
464 137
        return $fieldCollapsing->build($this);
465
    }
466
467
    /**
468
     * Applies a custom initialized grouping to the query.
469
     *
470
     * @param Grouping $grouping
471
     * @return $this
472
     */
473 137
    public function useGrouping(Grouping $grouping)
474
    {
475 137
        return $grouping->build($this);
476
    }
477
478
    /**
479
     * @param Highlighting $highlighting
480
     * @return $this
481
     */
482 136
    public function useHighlighting(Highlighting $highlighting)
483
    {
484 136
        return $highlighting->build($this);
485
    }
486
487
    /**
488
     * @param boolean $debugMode
489
     * @return $this
490
     */
491 35
    public function useDebug($debugMode)
492
    {
493 35
        if (!$debugMode) {
494 1
            $this->queryToBuild->addParam('debugQuery', null);
495 1
            $this->queryToBuild->addParam('echoParams', null);
496 1
            return $this;
497
        }
498
499 35
        $this->queryToBuild->addParam('debugQuery', 'true');
500 35
        $this->queryToBuild->addParam('echoParams', 'all');
501
502 35
        return $this;
503
    }
504
505
    /**
506
     * @param Elevation $elevation
507
     * @return QueryBuilder
508
     */
509 40
    public function useElevation(Elevation $elevation)
510
    {
511 40
        return $elevation->build($this);
512
    }
513
514
    /**
515
     * @param Spellchecking $spellchecking
516
     * @return $this
517
     */
518 35
    public function useSpellchecking(Spellchecking $spellchecking)
519
    {
520 35
        return $spellchecking->build($this);
521
    }
522
523
    /**
524
     * Applies a custom configured PhraseFields to the query.
525
     *
526
     * @param PhraseFields $phraseFields
527
     * @return $this
528
     */
529 138
    public function usePhraseFields(PhraseFields $phraseFields)
530
    {
531 138
        return $phraseFields->build($this);
532
    }
533
534
    /**
535
     * Applies a custom configured BigramPhraseFields to the query.
536
     *
537
     * @param BigramPhraseFields $bigramPhraseFields
538
     * @return $this
539
     */
540 137
    public function useBigramPhraseFields(BigramPhraseFields $bigramPhraseFields)
541
    {
542 137
        return $bigramPhraseFields->build($this);
543
    }
544
545
    /**
546
     * Applies a custom configured TrigramPhraseFields to the query.
547
     *
548
     * @param TrigramPhraseFields $trigramPhraseFields
549
     * @return $this
550
     */
551 137
    public function useTrigramPhraseFields(TrigramPhraseFields $trigramPhraseFields)
552
    {
553 137
        return $trigramPhraseFields->build($this);
554
    }
555
}