Query   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 76
c 1
b 0
f 0
dl 0
loc 151
rs 10
wmc 9

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getParams() 0 17 4
A getPlainQuery() 0 27 1
A __construct() 0 18 3
A getRegexQuery() 0 38 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Model;
6
7
/**
8
 * A Query produces the parameters needed to be passed to the CloudElastic service.
9
 */
10
class Query
11
{
12
    public const PRE_TAG = '%**%';
13
    public const POST_TAG = '*%%*';
14
    public const MAX_RESULTS = 5000;
15
16
    /** @var string The query string. */
17
    protected $query;
18
19
    /** @var int[] Array of namespace IDs. */
20
    protected $namespaces;
21
22
    /** @var bool Whether to get params for a regular expression search. */
23
    protected $regex;
24
25
    /** @var bool Whether the params should be for a case-insensitive search. */
26
    protected $ignoreCase;
27
28
    /** @var string Regular expression for page title. */
29
    protected $titlePattern;
30
31
    /**
32
     * Query constructor.
33
     * @param string $query
34
     * @param int[] $namespaces
35
     * @param bool $regex
36
     * @param bool $ignoreCase
37
     * @param string|null $titlePattern
38
     */
39
    public function __construct(
40
        string $query,
41
        array $namespaces,
42
        bool $regex = false,
43
        bool $ignoreCase = false,
44
        ?string $titlePattern = null
45
    ) {
46
        // Silently use regex to do exact match if query is wrapped in double-quotes.
47
        if ('"' === substr($query, 0, 1) && '"' === substr($query, -1, 1)) {
48
            $regex = true;
49
            $query = preg_quote(substr($query, 1, -1));
50
        }
51
52
        $this->query = $query;
53
        $this->namespaces = $namespaces;
54
        $this->regex = $regex;
55
        $this->ignoreCase = $ignoreCase;
56
        $this->titlePattern = $titlePattern;
57
    }
58
59
    /**
60
     * Get parameters needed to make the CloudElastic query.
61
     * @return array|mixed[]
62
     */
63
    public function getParams(): array
64
    {
65
        $params = $this->regex ? $this->getRegexQuery() : $this->getPlainQuery();
66
67
        if (!empty($this->namespaces)) {
68
            $params['query']['bool']['filter'][] = [ 'terms' => [
69
                'namespace' => $this->namespaces,
70
            ] ];
71
        }
72
73
        if ($this->titlePattern) {
74
            $params['query']['bool']['filter'][] = [ 'regexp' => [
75
                'title.keyword' => $this->titlePattern,
76
            ] ];
77
        }
78
79
        return $params;
80
    }
81
82
    /**
83
     * Params to be passed to CloudElastic for a plain (normal) query.
84
     * @return mixed[]
85
     */
86
    private function getPlainQuery(): array
87
    {
88
        return [
89
            'timeout' => '150s',
90
            'size' => self::MAX_RESULTS,
91
            '_source' => ['wiki', 'namespace_text', 'title'],
92
            'query' => [
93
                'bool' => [
94
                    'filter' => [
95
                        [ 'match' => [
96
                            'source_text.plain' => $this->query,
97
                        ] ],
98
                    ],
99
                ],
100
            ],
101
            'stats' => ['global-search'],
102
            'highlight' => [
103
                'pre_tags' => [self::PRE_TAG],
104
                'post_tags' => [self::POST_TAG],
105
                'fields' => [
106
                    'source_text.plain' => [
107
                        'type' => 'experimental',
108
                    ],
109
                ],
110
                'highlight_query' => [
111
                    'match' => [
112
                        'source_text.plain' => $this->query,
113
                    ],
114
                ],
115
            ],
116
        ];
117
    }
118
119
    /**
120
     * Params to be passed to CloudElastic for a regular expression query.
121
     * @return mixed[]
122
     */
123
    private function getRegexQuery(): array
124
    {
125
        return [
126
            'timeout' => '150s',
127
            'size' => 5000,
128
            '_source' => ['wiki', 'namespace_text', 'title'],
129
            'query' => [
130
                'bool' => [
131
                    'filter' => [
132
                        [ 'source_regex' => [
133
                            'regex' => $this->query,
134
                            'field' => 'source_text',
135
                            'ngram_field' => 'source_text.trigram',
136
                            'max_determinized_states' => 20000,
137
                            'max_expand' => 10,
138
                            'case_sensitive' => !$this->ignoreCase,
139
                            'locale' => 'en',
140
                        ] ],
141
                    ],
142
                ],
143
            ],
144
            'stats' => ['global-search'],
145
            'highlight' => [
146
                'pre_tags' => [self::PRE_TAG],
147
                'post_tags' => [self::POST_TAG],
148
                'fields' => [
149
                    'source_text.plain' => [
150
                        'type' => 'experimental',
151
                        'number_of_fragments' => 1,
152
                        'fragmenter' => 'scan',
153
                        'fragment_size' => 150,
154
                        'options' => [
155
                            'regex' => [$this->query],
156
                            'locale' => 'en',
157
                            'regex_flavor' => 'lucene',
158
                            'skip_query' => true,
159
                            'regex_case_insensitive' => $this->ignoreCase,
160
                            'max_determinized_states' => 20000,
161
                        ],
162
                    ],
163
                ],
164
            ],
165
        ];
166
    }
167
}
168