Completed
Push — master ( dafc58...e0fcd7 )
by
unknown
08:22 queued 06:36
created

TNTSearchEngine   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 194
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 7
dl 0
loc 194
rs 10
c 0
b 0
f 0

11 Methods

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