Passed
Pull Request — main (#63)
by Simon
01:15
created

ElasticIndex::shouldClear()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * class ElasticIndex|Firesphere\ElasticSearch\Indexes\ElasticIndex is the base for indexing items
4
 *
5
 * @package Firesphere\Elastic\Search
6
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
7
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
8
 */
9
10
namespace Firesphere\ElasticSearch\Indexes;
11
12
use Elastic\Elasticsearch\Exception\ClientResponseException;
13
use Elastic\Elasticsearch\Exception\MissingParameterException;
14
use Elastic\Elasticsearch\Exception\ServerResponseException;
15
use Firesphere\ElasticSearch\Queries\Builders\QueryBuilder;
16
use Firesphere\ElasticSearch\Queries\ElasticQuery;
17
use Firesphere\ElasticSearch\Results\SearchResult;
18
use Firesphere\ElasticSearch\Services\ElasticCoreService;
19
use Firesphere\ElasticSearch\Traits\IndexTraits\BaseIndexTrait;
20
use Firesphere\SearchBackend\Indexes\CoreIndex;
21
use Firesphere\SearchBackend\Traits\LoggerTrait;
22
use Firesphere\SearchBackend\Traits\QueryTraits\QueryFilterTrait;
23
use LogicException;
24
use Psr\Container\NotFoundExceptionInterface;
25
use SilverStripe\Control\HTTPRequest;
26
use SilverStripe\Core\Config\Configurable;
27
use SilverStripe\Core\Extensible;
28
use SilverStripe\Core\Injector\Injectable;
29
use SilverStripe\Core\Injector\Injector;
30
use SilverStripe\Dev\Deprecation;
31
32
/**
33
 * Base for managing a Elastic core.
34
 *
35
 * Base index settings and methods. Should be extended with at least a name for the index.
36
 * This is an abstract class that can not be instantiated on it's own
37
 *
38
 * @package Firesphere\Elastic\Search
39
 */
40
abstract class ElasticIndex extends CoreIndex
41
{
42
    use Extensible;
43
    use Configurable;
44
    use Injectable;
45
    use QueryFilterTrait;
46
    use BaseIndexTrait;
47
    use LoggerTrait;
48
49
    /**
50
     * @var array
51
     */
52
    protected $clientQuery;
53
54
    /**
55
     * @var array Classes to index
56
     */
57
    protected $class = [];
58
59
    public function __construct()
60
    {
61
        $this->client = Injector::inst()->get(ElasticCoreService::class)->getClient();
62
63
        $this->extend('onBeforeInit');
64
        $this->init();
65
        $this->extend('onAfterInit');
66
    }
67
68
69
    /**
70
     * Required to initialise the fields.
71
     * It's loaded in to the non-static properties for backward compatibility with FTS
72
     * Also, it's a tad easier to use this way, loading the other way around would be very
73
     * memory intensive, as updating the config for each item is not efficient
74
     */
75
    public function init()
76
    {
77
        $config = self::config()->get($this->getIndexName());
78
        if (!$config) {
79
            Deprecation::notice('5', 'Please set an index name and use a config yml');
80
        }
81
82
        if (!empty($this->getClasses())) {
83
            if (!$this->usedAllFields) {
84
                Deprecation::notice('5', 'It is advised to use a config YML for most cases');
85
            }
86
87
            return;
88
        }
89
90
        $this->initFromConfig($config);
91
    }
92
93
94
    /**
95
     * @param HTTPRequest|null $request
96
     * @return bool
97
     * @throws ClientResponseException
98
     * @throws MissingParameterException
99
     * @throws NotFoundExceptionInterface
100
     * @throws ServerResponseException
101
     */
102
    public function deleteIndex(HTTPRequest $request): bool
103
    {
104
        $deleteResult = false;
105
        if ($this->shouldClear($request) && $this->indexExists()) {
106
            $this->getLogger()->info(sprintf('Clearing index %s', $this->getIndexName()));
107
            $deleteResult = $this->client
108
                ->indices()
109
                ->delete(['index' => $this->getIndexName()])
110
                ->asBool();
0 ignored issues
show
Bug introduced by
The method asBool() does not exist on Http\Promise\Promise. ( Ignorable by Annotation )

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

110
                ->/** @scrutinizer ignore-call */ asBool();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
111
        }
112
113
        return $deleteResult;
114
    }
115
116
    /**
117
     * @param HTTPRequest|null $request
118
     * @return bool
119
     */
120
    private function shouldClear(?HTTPRequest $request = null): bool
121
    {
122
        if ($request !== null) {
123
            $var = $request->getVar('clear');
124
125
            return !empty($var);
126
        }
127
128
        return false;
129
    }
130
131
132
    /**
133
     * @return bool
134
     * @throws ClientResponseException
135
     * @throws MissingParameterException
136
     * @throws ServerResponseException
137
     */
138
    public function indexExists(): bool
139
    {
140
        return $this->getClient()
141
            ->indices()
142
            ->exists(['index' => $this->getIndexName()])
143
            ->asBool();
144
    }
145
146
    abstract public function getIndexName();
147
148
    /**
149
     * Get classes
150
     *
151
     * @return array
152
     */
153
    public function getClasses(): array
154
    {
155
        return $this->class;
156
    }
157
158
    /**
159
     * Generate the config from yml if possible
160
     * @param array|null $config
161
     */
162
    protected function initFromConfig($config): void
163
    {
164
        if (!$config || !array_key_exists('Classes', $config)) {
165
            throw new LogicException('No classes or config to index found!');
166
        }
167
168
        $this->setClasses($config['Classes']);
169
170
        // For backward compatibility, copy the config to the protected values
171
        // Saves doubling up further down the line
172
        foreach (parent::$fieldTypes as $type) {
173
            if (array_key_exists($type, $config)) {
174
                $method = 'set' . $type;
175
                if (method_exists($this, $method)) {
176
                    $this->$method($config[$type]);
177
                }
178
            }
179
        }
180
    }
181
182
    /**
183
     * Set the classes
184
     *
185
     * @param array $class
186
     * @return $this
187
     */
188
    public function setClasses($class): self
189
    {
190
        $this->class = $class;
191
192
        return $this;
193
    }
194
195
    /**
196
     * @param ElasticQuery $query
197
     * @return SearchResult
198
     * @throws ClientResponseException
199
     * @throws ServerResponseException
200
     */
201
    public function doSearch(ElasticQuery $query)
202
    {
203
        $this->clientQuery = QueryBuilder::buildQuery($query, $this);
204
205
        $result = $this->client->search($this->clientQuery);
206
207
        $result = new SearchResult($result, $query, $this);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type Http\Promise\Promise; however, parameter $result of Firesphere\ElasticSearch...chResult::__construct() does only seem to accept Elastic\Elasticsearch\Response\Elasticsearch, maybe add an additional type check? ( Ignorable by Annotation )

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

207
        $result = new SearchResult(/** @scrutinizer ignore-type */ $result, $query, $this);
Loading history...
208
209
        return $result;
210
    }
211
212
    /**
213
     * Add a class to index or query
214
     * $options is not used anymore, added for backward compatibility
215
     *
216
     * @param $class
217
     * @param array $options unused
218
     * @return $this
219
     */
220
    public function addClass($class, $options = []): self
221
    {
222
        $this->class[] = $class;
223
224
        return $this;
225
    }
226
227
    public function getClientQuery(): array
228
    {
229
        return $this->clientQuery;
230
    }
231
232
    public function setClientQuery(array $clientQuery): void
233
    {
234
        $this->clientQuery = $clientQuery;
235
    }
236
}
237