Completed
Push — master ( 4adefc...a1f354 )
by Hamoud
41:48 queued 28:10
created

ScoutElasticEngine   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 15
c 1
b 0
f 0
lcom 2
cbo 6
dl 0
loc 204
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B update() 0 24 3
A delete() 0 17 2
B search() 0 26 2
B paginate() 0 28 2
A mapIds() 0 4 1
A map() 0 22 3
A getTotalCount() 0 4 1
1
<?php
2
3
namespace Alhoqbani\Elastic;
4
5
use Elasticsearch\Client;
6
use Illuminate\Database\Eloquent\Collection;
7
use Laravel\Scout\Builder;
8
use Laravel\Scout\Engines\Engine;
9
10
class ScoutElasticEngine extends Engine
11
{
12
13
    /**
14
     * The Elasticsearch client.
15
     *
16
     * @var \Elasticsearch\Client
17
     */
18
    private $client;
19
20
    /**
21
     * ElasticSearchScoutEngine constructor.
22
     *
23
     * @param \Elasticsearch\Client $client
24
     */
25
    public function __construct(Client $client)
26
    {
27
        $this->client = $client;
28
    }
29
30
    /**
31
     * Update the given model in the index.
32
     *
33
     * @param  \Illuminate\Database\Eloquent\Collection $models
34
     *
35
     * @return void
36
     */
37
    public function update($models)
38
    {
39
        $index = $models->first()->searchableAs();
40
41
        $params = ['body' => []];
42
        foreach ($models as $model) {
43
            $array = $model->toSearchableArray();
44
45
            if (empty($array)) {
46
                return;
47
            }
48
49
            $params['body'][] = [
50
                'index' => [
51
                    '_index' => $index,
52
                    '_type'  => $index,
53
                    '_id'    => $model->getKey(),
54
                ],
55
            ];
56
            $params['body'][] = $array;
57
        }
58
59
        $this->client->bulk($params);
60
    }
61
62
    /**
63
     * Remove the given model from the index.
64
     *
65
     * @param  \Illuminate\Database\Eloquent\Collection $models
66
     *
67
     * @return void
68
     */
69
    public function delete($models)
70
    {
71
        $index = $models->first()->searchableAs();
72
73
        $params = ['body' => []];
74
        foreach ($models as $model) {
75
            $params['body'][] = [
76
                'delete' => [
77
                    '_index' => $index,
78
                    '_type'  => $index,
79
                    '_id'    => $model->getKey(),
80
                ],
81
            ];
82
        }
83
84
        $this->client->bulk($params);
85
    }
86
87
    /**
88
     * Perform the given search on the engine.
89
     *
90
     * @param  \Laravel\Scout\Builder $builder
91
     *
92
     * @return mixed
93
     */
94
    public function search(Builder $builder)
95
    {
96
        $params = [
97
            'index' => $builder->index ?? $builder->model->searchableAs(),
98
            'type'  => $builder->index ?? $builder->model->searchableAs(),
99
            'body'  => [
100
                'size'  => $builder->limit ?? $builder->model->getPerPage(),
101
                'query' => [
102
                    'multi_match' => [
103
                        'query'  => $builder->query,
104
                        'fields' => '_all',
105
                    ],
106
                ],
107
            ],
108
        ];
109
110
        if ($builder->callback) {
111
            $params =  call_user_func(
112
                $builder->callback,
113
                $this->client,
114
                $builder->query
115
            );
116
        }
117
118
        return $this->client->search($params);
119
    }
120
121
    /**
122
     * Perform the given search on the engine.
123
     *
124
     * @param  \Laravel\Scout\Builder $builder
125
     * @param  int                    $perPage
126
     * @param  int                    $page
127
     *
128
     * @return mixed
129
     */
130
    public function paginate(Builder $builder, $perPage, $page)
131
    {
132
        $params = [
133
            'index' => $builder->index ?? $builder->model->searchableAs(),
134
            'type'  => $builder->index ?? $builder->model->searchableAs(),
135
            'body'  => [
136
                'query' => [
137
                    'multi_match' => [
138
                        'query'  => $builder->query,
139
                        'fields' => '_all',
140
                    ],
141
                ],
142
            ],
143
        ];
144
145
        if ($builder->callback) {
146
            $params =  call_user_func(
147
                $builder->callback,
148
                $this->client,
149
                $builder->query
150
            );
151
        }
152
153
        $params['body']['size'] = $perPage;
154
        $params['body']['from'] = ($page - 1) * $perPage;
155
156
        return $this->client->search($params);
157
    }
158
159
    /**
160
     * Pluck and return the primary keys of the given results.
161
     *
162
     * @param  mixed $results
163
     *
164
     * @return \Illuminate\Support\Collection
165
     */
166
    public function mapIds($results)
167
    {
168
        return collect($results['hits']['hits'])->pluck('_id')->values();
169
    }
170
171
    /**
172
     * Map the given results to instances of the given model.
173
     *
174
     * @param  mixed                               $results
175
     * @param  \Illuminate\Database\Eloquent\Model $model
176
     *
177
     * @return \Illuminate\Database\Eloquent\Collection
178
     */
179
    public function map($results, $model)
180
    {
181
        if ($results['hits']['total'] === 0) {
182
            return Collection::make();
183
        }
184
185
        $keys = collect($results['hits']['hits'])
186
            ->pluck('_id')->values()->all();
187
188
        $models = $model->whereIn(
189
            $model->getQualifiedKeyName(),
190
            $keys
191
        )->get()->keyBy($model->getKeyName());
192
193
        return Collection::make($results['hits']['hits'])->map(function ($hit) use ($model, $models) {
194
            $key = $hit['_id'];
195
196
            if (isset($models[$key])) {
197
                return $models[$key];
198
            }
199
        })->filter()->values();
200
    }
201
202
    /**
203
     * Get the total count from a raw result returned by the engine.
204
     *
205
     * @param  mixed $results
206
     *
207
     * @return int
208
     */
209
    public function getTotalCount($results)
210
    {
211
        return $results['hits']['total'];
212
    }
213
}
214