Completed
Pull Request — master (#4)
by Hamoud
14:19
created

ScoutElasticEngine::update()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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