Completed
Push — master ( 03bb96...fda57c )
by Nenad
02:08
created

TNTSearchEngine::map()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 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
        $models->each(function ($model) {
38
            $searchableFields = $model->toSearchableArray();
39
40
            $this->tnt->selectIndex("{$model->searchableAs()}.index");
41
            $index = $this->tnt->getIndex();
42
            $index->setPrimaryKey($model->getKeyName());
43
44
            if ($model->getKey()) {
45
                $index->update($model->getKey(), $searchableFields);
46
            } else {
47
                $index->insert($searchableFields);
48
            }
49
        });
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
        $builder->limit = 500;
94
        $results        = $this->performSearch($builder);
95
        $chunks         = array_chunk($results['ids'], $perPage);
96
97
        if (!empty($chunks)) {
98
            if (array_key_exists($page - 1, $chunks)) {
99
                $results['ids'] = $chunks[$page - 1];
100
            } else {
101
                $results['ids'] = end($chunks);
102
            }
103
        }
104
105
        return $results;
106
    }
107
108
    /**
109
     * Perform the given search on the engine.
110
     *
111
     * @param Builder $builder
112
     *
113
     * @return mixed
114
     */
115
    protected function performSearch(Builder $builder)
116
    {
117
        $index = $builder->index ?: $builder->model->searchableAs();
118
        $limit = $builder->limit ?: 10;
119
        $this->tnt->selectIndex("{$index}.index");
120
121
        return $this->tnt->search($builder->query, $limit);
122
    }
123
124
    /**
125
     * Get the filter array for the query.
126
     *
127
     * @param Builder $builder
128
     *
129
     * @return array
130
     */
131
    protected function filters(Builder $builder)
132
    {
133
        return collect($builder->wheres)->map(function ($value, $key) {
134
            return $key.'='.$value;
135
        })->values()->all();
136
    }
137
138
    /**
139
     * Map the given results to instances of the given model.
140
     *
141
     * @param mixed                               $results
142
     * @param \Illuminate\Database\Eloquent\Model $model
143
     *
144
     * @return Collection
145
     */
146
    public function map($results, $model)
147
    {
148
        if (count($results['ids']) === 0) {
149
            return Collection::make();
150
        }
151
        
152
        $keys   = collect($results['ids']);
153
        $models = $model->whereIn(
154
            $model->getKeyName(), $keys
155
        )->get()->keyBy($model->getKeyName());
156
157
        return collect($results['ids'])->map(function ($hit) use ($models) {
158
            return $models[$hit];
159
        });
160
    }
161
162
    /**
163
     * Get the total count from a raw result returned by the engine.
164
     *
165
     * @param  mixed  $results
166
     * @return int
167
     */
168
    public function getTotalCount($results)
169
    {
170
        return count($results['ids']);
171
    }
172
173
    public function initIndex($model)
174
    {
175
        $indexName = $model->searchableAs();
176
177
        if (!file_exists($this->tnt->config['storage']."/{$indexName}.index")) {
178
            $indexer = $this->tnt->createIndex("$indexName.index");
179
            $indexer->setDatabaseHandle($model->getConnection()->getPdo());
180
            $indexer->disableOutput = true;
181
            $indexer->setPrimaryKey($model->getKeyName());
182
            $fields = implode(', ', array_keys($model->toSearchableArray()));
183
            $indexer->query("SELECT {$model->getKeyName()}, $fields FROM {$model->getTable()} WHERE {$model->getKeyName()} = {$model->getKey()}");
184
            $indexer->run();
185
        }
186
    }
187
}
188