SolrEngine   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 212
Duplicated Lines 0 %

Importance

Changes 7
Bugs 1 Features 0
Metric Value
wmc 20
eloc 60
c 7
b 1
f 0
dl 0
loc 212
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A delete() 0 16 2
A filters() 0 5 1
A map() 0 17 3
A update() 0 30 3
A flush() 0 8 3
A getTotalCount() 0 3 1
A performSearch() 0 16 3
A mapIds() 0 7 1
A search() 0 3 1
A paginate() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ScoutEngines\Solr;
6
7
use Illuminate\Database\Eloquent\Collection;
8
use Laravel\Scout\Builder;
9
use Laravel\Scout\Engines\Engine;
10
use Solarium\Client;
11
12
class SolrEngine extends Engine
13
{
14
    /**
15
     * @var Client
16
     */
17
    private $client;
18
19
    /**
20
     * SolrEngine constructor.
21
     *
22
     * @param Client $client
23
     */
24
    public function __construct(Client $client)
25
    {
26
        $this->client = $client;
27
    }
28
29
    /**
30
     * Update the given model in the index.
31
     *
32
     * @param  \Illuminate\Database\Eloquent\Collection $models
33
     * @return void
34
     */
35
    public function update($models)
36
    {
37
        if ($models->isEmpty()) {
38
            return;
39
        }
40
41
        $query = $this->client->createUpdate();
42
43
        $models->each(function ($model) use (&$query) {
44
            $attrs = array_filter($model->toSearchableArray(), function ($value) {
45
                return !\is_null($value);
46
            });
47
48
            // Make sure there is an ID in the array,
49
            // otherwise we will create duplicates all the time.
50
            if (!\array_key_exists('id', $attrs)) {
51
                $attrs['id'] = $model->getScoutKey();
52
            }
53
54
            // Add model class to attributes for flushing.
55
            $attrs['_class'] = \get_class($model);
56
57
            $document = $query->createDocument($attrs);
58
            $query->addDocument($document);
59
        });
60
61
        $query->addCommit();
62
63
        $endpoint = $models->first()->searchableAs();
64
        $this->client->update($query, $endpoint);
65
    }
66
67
    /**
68
     * Remove the given model from the index.
69
     *
70
     * @param  \Illuminate\Database\Eloquent\Collection $models
71
     * @return void
72
     */
73
    public function delete($models)
74
    {
75
        if ($models->isEmpty()) {
76
            return;
77
        }
78
79
        $ids = $models->map(function ($model) {
80
            return $model->getScoutKey();
81
        });
82
83
        $query = $this->client->createUpdate();
84
        $query->addDeleteByIds($ids->toArray());
85
        $query->addCommit();
86
87
        $endpoint = $models->first()->searchableAs();
88
        $this->client->update($query, $endpoint);
89
    }
90
91
    /**
92
     * Perform the given search on the engine.
93
     *
94
     * @param  \Laravel\Scout\Builder $builder
95
     * @return mixed
96
     */
97
    public function search(Builder $builder)
98
    {
99
        return $this->performSearch($builder);
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
     * @return mixed
109
     */
110
    public function paginate(Builder $builder, $perPage, $page)
111
    {
112
        $offset = ($page - 1) * $perPage;
113
114
        return $this->performSearch($builder, $perPage, $offset);
115
    }
116
117
    /**
118
     * Pluck and return the primary keys of the given results.
119
     *
120
     * @param  \Solarium\QueryType\Select\Result\Result $results
121
     * @return \Illuminate\Support\Collection
122
     */
123
    public function mapIds($results)
124
    {
125
        $ids = array_map(function ($document) {
126
            return $document->id;
127
        }, $results->getDocuments());
128
129
        return collect($ids);
130
    }
131
132
    /**
133
     * Map the given results to instances of the given model.
134
     *
135
     * @param  \Laravel\Scout\Builder $builder
136
     * @param  \Solarium\QueryType\Select\Result\Result $results
137
     * @param  \Illuminate\Database\Eloquent\Model $model
138
     * @return \Illuminate\Database\Eloquent\Collection
139
     */
140
    public function map(Builder $builder, $results, $model)
141
    {
142
        if (\count($results->getDocuments()) === 0) {
143
            return Collection::make();
144
        }
145
146
        $models = $model->getScoutModelsByIds(
147
            $builder, collect($results->getDocuments())->pluck('id')->values()->all()
148
        )->keyBy(function ($model) {
149
            return $model->getScoutKey();
150
        });
151
152
        return Collection::make($results->getDocuments())->map(function ($document) use ($models) {
153
            if (isset($models[$document['id']])) {
154
                return $models[$document['id']];
155
            }
156
        })->filter()->values();
157
    }
158
159
    /**
160
     * Get the total count from a raw result returned by the engine.
161
     *
162
     * @param  \Solarium\QueryType\Select\Result\Result $results
163
     * @return int
164
     */
165
    public function getTotalCount($results)
166
    {
167
        return $results->getNumFound();
168
    }
169
170
    /**
171
     * Flush all of the model's records from the engine.
172
     *
173
     * @param  \Illuminate\Database\Eloquent\Model  $model
174
     * @return void
175
     */
176
    public function flush($model)
177
    {
178
        $class = \is_object($model) ? \get_class($model) : false;
179
        if ($class) {
180
            $query = $this->client->createUpdate();
181
            $query->addDeleteQuery("_class:{$class}");
182
            $query->addCommit();
183
            $this->client->update($query);
184
        }
185
    }
186
187
    /**
188
     * Perform the given search on the engine.
189
     *
190
     * @param  \Laravel\Scout\Builder  $builder
191
     * @param  int|null $perPage
192
     * @param  int|null $offset
193
     * @return mixed
194
     */
195
    protected function performSearch(Builder $builder, $perPage = null, $offset = null)
196
    {
197
        $selectQuery = $this->client->createSelect();
198
199
        $conditions = (empty($builder->query)) ? [] : [$builder->query];
200
        $conditions = array_merge($conditions, $this->filters($builder));
201
202
        $selectQuery->setQuery(implode(' ', $conditions));
203
204
        if (!\is_null($perPage)) {
205
            $selectQuery->setStart($offset)->setRows($perPage);
206
        }
207
208
        // @todo callback return
209
210
        return $this->client->select($selectQuery);
211
    }
212
213
    /**
214
     * Get the filter array for the query.
215
     *
216
     * @param  \Laravel\Scout\Builder  $builder
217
     * @return array
218
     */
219
    protected function filters(Builder $builder)
220
    {
221
        return collect($builder->wheres)->map(function ($value, $key) {
222
            return sprintf('%s:"%s"', $key, $value);
223
        })->values()->all();
224
    }
225
}
226