Passed
Branch master (561ab7)
by Arun
02:07
created

ElasticSearchEngine::filters()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 8
rs 10
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: arun
5
 * Date: 2019-07-07
6
 * Time: 12:59
7
 */
8
9
namespace ArunFung\ScoutElasticSearch;
10
11
use Laravel\Scout\Builder;
12
use Laravel\Scout\Engines\Engine;
13
use Elasticsearch\Client as ElasticSearch;
14
use Illuminate\Database\Eloquent\Model;
15
use Illuminate\Database\Eloquent\Collection;
16
17
/**
18
 * Class ElasticSearchEngine
19
 * @package ArunFung\ScoutElasticSearch
20
 */
21
class ElasticSearchEngine extends Engine
22
{
23
    /**
24
     * ElasticSearch instance
25
     *
26
     * @var ElasticSearch
27
     */
28
    protected $elasticSearch;
29
30
    /**
31
     * @var ElasticSearch Index
32
     */
33
    protected $index;
34
35
    /**
36
     * Create a new engine instance.
37
     *
38
     * @param ElasticSearch $elasticSearch
39
     * @param  $index
40
     * @return void
41
     */
42
    public function __construct(ElasticSearch $elasticSearch, $index)
43
    {
44
        $this->elasticSearch = $elasticSearch;
45
        $this->index = $index;
46
    }
47
48
    /**
49
     * Update the given model in the index.
50
     *
51
     * @param Collection $models
52
     * @return void
53
     */
54
    public function update($models)
55
    {
56
        $params = [];
57
        $models->each(function ($model) use (&$params) {
58
            $params['body'][] = [
59
                'index' => [
60
                    '_index' => $this->index,
61
                    '_type' => $model->searchableAs(),
62
                    '_id' => $model->getScoutKey()
63
                ]
64
            ];
65
            $params['body'][] = $model->toSearchableArray();
66
        });
67
68
        $this->elasticSearch->bulk($params);
69
    }
70
71
    /**
72
     * Remove the given model from the index.
73
     *
74
     * @param Collection $models
75
     * @return void
76
     */
77
    public function delete($models)
78
    {
79
        $params = [];
80
        $models->each(function ($model) use (&$params) {
81
            $params['body'][] = [
82
                'delete' => [
83
                    '_index' => $this->index,
84
                    '_type' => $model->searchableAs(),
85
                    '_id' => $model->getScoutKey()
86
                ]
87
            ];
88
        });
89
        $this->elasticSearch->bulk($params);
90
    }
91
92
    /**
93
     * Perform the given search on the engine.
94
     *
95
     * @param \Laravel\Scout\Builder $builder
96
     * @return mixed
97
     */
98
    public function search(Builder $builder)
99
    {
100
        // TODO: Implement search() method.
101
    }
102
103
    /**
104
     * Perform the given search on the engine.
105
     *
106
     * @param Builder $builder
107
     * @param int $perPage
108
     * @param int $page
109
     * @return mixed
110
     */
111
    public function paginate(Builder $builder, $perPage, $page)
112
    {
113
        $options = [
114
            'numericFilters' => $this->filters($builder),
115
            'from' => (($page - 1) * $perPage),
116
            'size' => $perPage,
117
        ];
118
119
        return $this->performSearch($builder, $options);
120
    }
121
122
    /**
123
     * Perform the given search on the engine.
124
     *
125
     * @param Builder $builder
126
     * @param array $options
127
     * @return mixed
128
     */
129
    protected function performSearch(Builder $builder, array $options = [])
130
    {
131
        $params = [
132
            'index' => $this->index,
133
            'type' => $builder->model->searchableAs(),
134
        ];
135
136
        $must = [['query_string' => ['query' => "*{$builder->query}*"]]];
137
138
        if (isset($options['numericFilters']) && count($options['numericFilters'])) {
139
            $must = array_merge($must, $options['numericFilters']);
140
        }
141
142
        $body = [
143
            'query' => [
144
                'bool' => [
145
                    'must' => $must
146
                ]
147
            ]
148
        ];
149
150
        if (isset($options['from'])) {
151
            $body['from'] = $options['from'];
152
        }
153
154
        if (isset($options['size'])) {
155
            $body['size'] = $options['size'];
156
        }
157
158
        $params['body'] = $body;
159
160
        if ($builder->callback) {
161
            return call_user_func(
162
                $builder->callback,
163
                $this->elasticSearch,
164
                $builder->query,
165
                $params
166
            );
167
        }
168
169
        return $this->elasticSearch->search();
170
    }
171
172
    /**
173
     * Get the filter array for the query.
174
     *
175
     * @param Builder $builder
176
     * @return array
177
     */
178
    protected function filters(Builder $builder)
179
    {
180
        return collect($builder->wheres)->map(function ($value, $key) {
181
            if (is_array($value)) {
182
                return ['terms' => [$key => $value]];
183
            }
184
            return ['match_phrase' => [$key => $value]];
185
        })->values()->all();
186
    }
187
188
    /**
189
     * Pluck and return the primary keys of the given results.
190
     *
191
     * @param mixed $results
192
     * @return \Illuminate\Support\Collection
193
     */
194
    public function mapIds($results)
195
    {
196
        return collect($results['hits']['hits'])->pluck('_id');
197
    }
198
199
    /**
200
     * Map the given results to instances of the given model.
201
     *
202
     * @param Builder $builder
203
     * @param mixed $results
204
     * @param Model $model
205
     * @return Collection
206
     */
207
    public function map(Builder $builder, $results, $model)
208
    {
209
        if ($this->getTotalCount($results) == 0) {
210
            return $model->newCollection();
211
        }
212
213
        $ids = $this->mapIds($results)->all();
214
215
        return $model->getScoutModelsByIds($builder, $ids)->filter(function ($model) use ($ids) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return $model->getScoutM...ion(...) { /* ... */ }) also could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Collection.
Loading history...
216
            return in_array($model->getScoutKey(), $ids);
217
        });
218
    }
219
220
    /**
221
     * Get the total count from a raw result returned by the engine.
222
     *
223
     * @param mixed $results
224
     * @return int
225
     */
226
    public function getTotalCount($results)
227
    {
228
        return $results['hits']['total']['value'];
229
    }
230
231
    /**
232
     * Flush all of the model's records from the engine.
233
     *
234
     * @param Model $model
235
     * @return void
236
     */
237
    public function flush($model)
238
    {
239
        $model->newQuery()->orderBy($model->getKeyName())->unsearchable();
240
    }
241
}
242