Completed
Pull Request — master (#77)
by
unknown
06:06
created

TNTSearchEngine::performSearch()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 4
nop 1
1
<?php
2
3
namespace TeamTNT\Scout\Engines;
4
5
use Illuminate\Database\Eloquent\Collection;
6
use Laravel\Scout\Builder;
7
use Laravel\Scout\Engines\Engine;
8
use TeamTNT\TNTSearch\TNTSearch;
9
10
class TNTSearchEngine extends Engine
11
{
12
    /**
13
     * @var TNTSearch
14
     */
15
    protected $tnt;
16
17
    /**
18
     * @var Builder
19
     */
20
    protected $builder;
21
22
    /**
23
     * Create a new engine instance.
24
     *
25
     * @param TNTSearch $tnt
26
     */
27
    public function __construct(TNTSearch $tnt)
28
    {
29
        $this->tnt = $tnt;
30
    }
31
32
    /**
33
     * Update the given model in the index.
34
     *
35
     * @param Collection $models
36
     *
37
     * @return void
38
     */
39
    public function update($models)
40
    {
41
        $this->initIndex($models->first());
42
        $this->tnt->selectIndex("{$models->first()->searchableAs()}.index");
43
        $index = $this->tnt->getIndex();
44
        $index->setPrimaryKey($models->first()->getKeyName());
45
46
        $index->indexBeginTransaction();
47
        $models->each(function ($model) use ($index) {
48
            if ($model->getKey()) {
49
                $index->update($model->getKey(), $model->toSearchableArray());
50
            } else {
51
                $index->insert($model->toSearchableArray());
52
            }
53
        });
54
        $index->indexEndTransaction();
55
    }
56
57
    /**
58
     * Remove the given model from the index.
59
     *
60
     * @param Collection $models
61
     *
62
     * @return void
63
     */
64
    public function delete($models)
65
    {
66
        $this->initIndex($models->first());
67
        $models->each(function ($model) {
68
            $this->tnt->selectIndex("{$model->searchableAs()}.index");
69
            $index = $this->tnt->getIndex();
70
            $index->setPrimaryKey($model->getKeyName());
71
            $index->delete($model->getKey());
72
        });
73
    }
74
75
    /**
76
     * Perform the given search on the engine.
77
     *
78
     * @param Builder $builder
79
     *
80
     * @return mixed
81
     */
82
    public function search(Builder $builder)
83
    {
84
        return $this->performSearch($builder);
85
    }
86
87
    /**
88
     * Perform the given search on the engine.
89
     *
90
     * @param Builder $builder
91
     * @param int     $perPage
92
     * @param int     $page
93
     *
94
     * @return mixed
95
     */
96
    public function paginate(Builder $builder, $perPage, $page)
97
    {
98
        $results = $this->performSearch($builder);
99
100
        if ($builder->limit) {
101
            $results['hits'] = $builder->limit;
102
        }
103
104
        $chunks = array_chunk($results['ids'], $perPage);
105
106
        if (!empty($chunks)) {
107
            if (array_key_exists($page - 1, $chunks)) {
108
                $results['ids'] = $chunks[$page - 1];
109
            } else {
110
                $results['ids'] = end($chunks);
111
            }
112
        }
113
114
        return $results;
115
    }
116
117
    /**
118
     * Perform the given search on the engine.
119
     *
120
     * @param Builder $builder
121
     *
122
     * @return mixed
123
     */
124
    protected function performSearch(Builder $builder)
125
    {
126
        $index = $builder->index ?: $builder->model->searchableAs();
127
        $limit = $builder->limit ?: 10000;
128
        $this->tnt->selectIndex("{$index}.index");
129
130
        $this->builder = $builder;
131
132
        return $this->tnt->search($builder->query, $limit);
133
    }
134
135
    /**
136
     * Get the filter array for the query.
137
     *
138
     * @param Builder $builder
139
     *
140
     * @return array
141
     */
142
    protected function filters(Builder $builder)
143
    {
144
        return collect($builder->wheres)->map(function ($value, $key) {
145
            return $key.'='.$value;
146
        })->values()->all();
147
    }
148
149
    /**
150
     * Map the given results to instances of the given model.
151
     *
152
     * @param mixed                               $results
153
     * @param \Illuminate\Database\Eloquent\Model $model
154
     *
155
     * @return Collection
156
     */
157
    public function map($results, $model)
158
    {
159
        if (count($results['ids']) === 0) {
160
            return Collection::make();
161
        }
162
163
        $keys   = collect($results['ids'])->values()->all();
164
        $fieldsWheres = array_keys($this->builder->wheres);
165
        $models = $model->whereIn(
166
            $model->getQualifiedKeyName(), $keys
167
        )->get()->keyBy($model->getKeyName());
168
169
        return collect($results['ids'])->map(function ($hit) use ($models) {
170
            return $models->has($hit) ? $models[$hit] : null;
171
        })->filter(function ($model) use ($fieldsWheres) {
172
            return !is_null($model) && array_reduce($fieldsWheres, function ($carry, $item) use($model) {
173
                    return $carry && $model[$item] == $this->builder->wheres[$item];
174
                }, true);;
175
        });
176
    }
177
178
    /**
179
     * Pluck and return the primary keys of the given results.
180
     *
181
     * @param mixed $results
182
     * @return \Illuminate\Support\Collection
183
     */
184
    public function mapIds($results)
185
    {
186
        return collect($results['ids'])->values();
187
    }
188
189
    /**
190
     * Get the total count from a raw result returned by the engine.
191
     *
192
     * @param mixed $results
193
     *
194
     * @return int
195
     */
196
    public function getTotalCount($results)
197
    {
198
        return $results['hits'];
199
    }
200
201
    public function initIndex($model)
202
    {
203
        $indexName = $model->searchableAs();
204
205
        if (!file_exists($this->tnt->config['storage']."/{$indexName}.index")) {
206
            $indexer = $this->tnt->createIndex("$indexName.index");
207
            $indexer->setDatabaseHandle($model->getConnection()->getPdo());
208
            $indexer->setPrimaryKey($model->getKeyName());
209
        }
210
    }
211
}
212