Passed
Push — hans/or-we-start-or-facets ( ebf2cb...dec393 )
by Simon
05:47 queued 01:12
created

QueryComponentFacetTrait::createFacetCriteria()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
c 0
b 0
f 0
nc 4
nop 3
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 3
rs 10
1
<?php
2
/**
3
 * Trait QueryComponentFacetTrait|Firesphere\SolrSearch\Traits\QueryComponentFacetTrait Trait to set Faceting on fields
4
 * for the {@link \Firesphere\SolrSearch\Factories\QueryComponentFactory}
5
 *
6
 * @package Firesphere\SolrSearch\Traits
7
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
8
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
9
 */
10
11
namespace Firesphere\SolrSearch\Traits;
12
13
use Firesphere\SolrSearch\Indexes\BaseIndex;
14
use Firesphere\SolrSearch\Queries\BaseQuery;
15
use Minimalcode\Search\Criteria;
16
use SilverStripe\Core\ClassInfo;
17
use Solarium\Component\Facet\Field;
18
use Solarium\QueryType\Select\Query\Query;
19
20
/**
21
 * Trait QueryComponentFacetTrait deals with the facets.
22
 *
23
 * Faceting for any given query or index.
24
 *
25
 * @package Firesphere\SolrSearch\Traits
26
 */
27
trait QueryComponentFacetTrait
28
{
29
    /**
30
     * @var BaseIndex Index to query
31
     */
32
    protected $index;
33
    /**
34
     * @var BaseQuery Query to use
35
     */
36
    protected $query;
37
    /**
38
     * @var Query Solarium query
39
     */
40
    protected $clientQuery;
41
42
    /**
43
     * Add facets from the index, to make sure Solr returns
44
     * the expected facets and their respective count on the
45
     * correct fields
46
     */
47 9
    protected function buildQueryFacets(): void
48
    {
49 9
        $facets = $this->clientQuery->getFacetSet();
50 9
        $facetSets = array_merge($this->index->getFacetFields(), $this->index->getOrFacetFields());
51
        // Facets should be set from the index configuration
52 9
        foreach ($facetSets as $config) {
53 2
            $shortClass = getShortFieldName($config['BaseClass']);
54 2
            $field = $shortClass . '_' . str_replace('.', '_', $config['Field']);
55
            /** @var Field $facet */
56 2
            $facet = $facets->createFacetField('facet-' . $config['Title']);
57 2
            $facet->setField($field);
58
        }
59
        // Count however, comes from the query
60 9
        $facets->setMinCount($this->query->getFacetsMinCount());
61 9
    }
62
63
    /**
64
     * Add AND facet filters based on the current request
65
     */
66 9
    protected function buildAndFacetFilterQuery()
67
    {
68 9
        $filterFacets = $this->query->getAndFacetFilter();
69
        /** @var null|Criteria $criteria */
70 9
        $criteria = null;
71 9
        foreach ($this->index->getFacetFields() as $config) {
72 2
            if (isset($filterFacets[$config['Title']])) {
73
                // For the API generator, this needs to be old style list();
74 1
                list($filter, $field) = $this->getFieldFacets($filterFacets, $config);
75 2
                $this->createFacetCriteria($criteria, $field, $filter);
76
            }
77
        }
78 9
        if ($criteria) {
79 1
            $this->clientQuery
80 1
                ->createFilterQuery('andFacets')
81 1
                ->setQuery($criteria->getQuery());
82
        }
83 9
    }
84
85
    /**
86
     * Add OR facet filters based on the current request
87
     */
88 9
    protected function buildOrFacetFilterQuery()
89
    {
90 9
        $filterFacets = $this->query->getOrFacetFilter();
91 9
        $i = 0;
92
        /** @var null|Criteria $criteria */
93 9
        foreach ($this->index->getOrFacetFields() as $class => $config) {
94
            $criteria = null;
95
            if (isset($filterFacets[$config['Title']])) {
96
                // For the API generator, this needs to be old style list();
97
                list($filter, $field) = $this->getFieldFacets($filterFacets, $config);
98
                $this->createFacetCriteria($criteria, $field, $filter);
99
                $this->clientQuery
100
                    ->createFilterQuery('orFacet-' . $i++)
101
                    ->setQuery($criteria->getQuery());
102
            }
103
        }
104 9
    }
105
106
    /**
107
     * Get the field and it's respected values to filter on to generate Criteria from
108
     *
109
     * @param array $filterFacets
110
     * @param array $config
111
     * @return array
112
     */
113 1
    protected function getFieldFacets(array $filterFacets, $config): array
114
    {
115 1
        $filter = $filterFacets[$config['Title']];
116 1
        $filter = is_array($filter) ? $filter : [$filter];
117
        // Fields are "short named" for convenience
118 1
        $shortClass = getShortFieldName($config['BaseClass']);
119 1
        $field = $shortClass . '_' . str_replace('.', '_', $config['Field']);
120
121 1
        return [$filter, $field];
122
    }
123
124
    /**
125
     * Combine all facets as AND facet filters for the results
126
     *
127
     * @param null|Criteria $criteria
128
     * @param string $field
129
     * @param array $filter
130
     */
131 1
    protected function createFacetCriteria(&$criteria, string $field, array $filter)
132
    {
133
        // If the criteria is empty, create a new one with a value from the filter array
134 1
        if (!$criteria) {
135 1
            $criteria = Criteria::where($field)->is(array_pop($filter));
136
        }
137
        // Add the other items in the filter array, as an AND
138 1
        foreach ($filter as $filterValue) {
139 1
            $criteria->andWhere($field)->is($filterValue);
140
        }
141 1
    }
142
}
143