Completed
Push — dev ( d4c32c...f7539b )
by Darko
14:51
created

SphinxSearch::searchIndexes()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 7
Bugs 1 Features 0
Metric Value
eloc 14
c 7
b 1
f 0
dl 0
loc 19
ccs 0
cts 0
cp 0
rs 9.2222
cc 6
nc 7
nop 4
crap 42
1
<?php
2
3
namespace Blacklight;
4
5
use App\Models\Predb;
6
use App\Models\Release;
7
use Foolz\SphinxQL\Drivers\Pdo\Connection;
8
use Foolz\SphinxQL\Exception\DatabaseException;
9
use Foolz\SphinxQL\Exception\SphinxQLException;
10
use Foolz\SphinxQL\Helper;
11
use Foolz\SphinxQL\SphinxQL;
12
use Illuminate\Support\Facades\DB;
13
14
/**
15
 * Class SphinxSearch.
16
 */
17
class SphinxSearch
18
{
19
    /**
20
     * @var \Foolz\SphinxQL\SphinxQL
21
     */
22
    public $sphinxQL;
23
24
    /**
25
     * @var \Foolz\SphinxQL\Drivers\Pdo\Connection
26
     */
27
    protected $connection;
28
29
    /**
30
     * @var \Illuminate\Config\Repository|mixed
31
     */
32
    protected $config;
33
34
    /**
35
     * @var \Foolz\SphinxQL\Helper
36
     */
37
    protected $helper;
38
39
    /**
40
     * @var \Blacklight\ColorCLI
41
     */
42
    private $cli;
43
44
    /**
45
     * Establish connection to SphinxQL.
46
     *
47
     * @throws \Exception
48
     */
49
    public function __construct()
50
    {
51
        $this->connection = new Connection();
52
        $this->config = config('sphinxsearch');
53
        $this->connection->setParams(['host' => $this->config['host'], 'port' => $this->config['port']]);
54
        $this->sphinxQL = new SphinxQL($this->connection);
55
        $this->helper = new Helper($this->connection);
56
        $this->cli = new ColorCLI();
57
    }
58
59
    /**
60
     * Insert release into Sphinx RT table.
61
     * @param $parameters
62
     * @throws \Foolz\SphinxQL\Exception\ConnectionException
63
     * @throws \Foolz\SphinxQL\Exception\DatabaseException
64
     * @throws \Foolz\SphinxQL\Exception\SphinxQLException
65
     */
66
    public function insertRelease($parameters): void
67
    {
68
        if ($this->sphinxQL !== null && $parameters['id']) {
69
            $this->sphinxQL
70
                ->replace()
71
                ->into($this->config['indexes']['releases'])
72
                ->set(['id' => $parameters['id'], 'name' => $parameters['name'], 'searchname' => $parameters['searchname'], 'fromname' => $parameters['fromname'], 'filename' => empty($parameters['filename']) ? "''" : $parameters['filename']])
73
                ->execute();
74
        }
75
    }
76
77
    /**
78
     * Insert release into Sphinx RT table.
79
     * @param $parameters
80
     * @throws \Foolz\SphinxQL\Exception\ConnectionException
81
     * @throws \Foolz\SphinxQL\Exception\DatabaseException
82
     * @throws \Foolz\SphinxQL\Exception\SphinxQLException
83
     */
84
    public function insertPredb($parameters): void
85
    {
86
        if ($this->sphinxQL !== null && $parameters['id']) {
87
            $this->sphinxQL
88
                ->replace()
89
                ->into($this->config['indexes']['predb'])
90
                ->set(['id' => $parameters['id'], 'title' => $parameters['title'], 'filename' => empty($parameters['filename']) ? "''" : $parameters['filename'], 'source' => $parameters['source']])
91
                ->execute();
92
        }
93
    }
94
95
    /**
96
     * Delete release from Sphinx RT tables.
97
     * @param array $identifiers ['g' => Release GUID(mandatory), 'id' => ReleaseID(optional, pass false)]
98
     */
99
    public function deleteRelease($identifiers): void
100
    {
101
        if ($identifiers['i'] === false) {
102
            $identifiers['i'] = Release::query()->where('guid', $identifiers['g'])->first(['id']);
103
            if ($identifiers['i'] !== null) {
104
                $identifiers['i'] = $identifiers['i']['id'];
105
            }
106
        }
107
        if ($identifiers['i'] !== false) {
108
            $this->sphinxQL->delete()->from([$this->config['indexes']['releases']])->where('id', '=', $identifiers['i']);
109
        }
110
    }
111
112
    /**
113
     * Escapes characters that are treated as special operators by the query language parser.
114
     *
115
     * @param string $string unescaped string
116
     *
117
     * @return string Escaped string.
118
     */
119
    public static function escapeString($string): string
120
    {
121
        $from = ['\\', '(', ')', '|', '-', '!', '@', '~', '"', '&', '/', '^', '$', '=', "'"];
122
        $to = ['\\\\', '\(', '\)', '\|', '\-', '\!', '\@', '\~', '\"', '\&', '\/', '\^', '\$', '\=', "\'"];
123
124
        return str_replace($from, $to, $string);
125
    }
126
127
    /**
128
     * Update Sphinx Relases index for given releases_id.
129
     *
130
     * @param int $releaseID
131
     * @throws \Exception
132
     */
133
    public function updateRelease($releaseID): void
134
    {
135
        $new = Release::query()
136
                ->where('releases.id', $releaseID)
137
                ->leftJoin('release_files as rf', 'releases.id', '=', 'rf.releases_id')
138
                ->select(['releases.id', 'releases.name', 'releases.searchname', 'releases.fromname', DB::raw('IFNULL(GROUP_CONCAT(rf.name SEPARATOR " "),"") filename')])
139
                ->groupBy('releases.id')
140
                ->first();
141
142
        if ($new !== null) {
143
            $this->insertRelease($new);
144
        }
145
    }
146
147
    /**
148
     * Update Sphinx Predb index for given predb_id.
149
     *
150
     * @param array $parameters
151
     * @throws \Exception
152
     */
153
    public function updatePreDb($parameters): void
154
    {
155
        if (! empty($parameters)) {
156
            $this->insertPredb($parameters);
157
        }
158
    }
159
160
    /**
161
     * Truncate the RT index.
162
     *
163
     * @param array $indexes
164
     * @return bool
165
     */
166
    public function truncateRTIndex($indexes = []): bool
167
    {
168
        if (empty($indexes)) {
169
            $this->cli->error('You need to provide index name to truncate');
170
171
            return false;
172
        }
173
        foreach ($indexes as $index) {
174
            if (\in_array($index, $this->config['indexes'], true)) {
175
                $this->helper->truncateRtIndex($index);
176
                $this->cli->info('Truncating index '.$index.' finished.');
177
            } else {
178
                $this->cli->error('Unsupported index: '.$index);
179
            }
180
        }
181
182
        return true;
183
    }
184
185
    /**
186
     * Optimize the RT index.
187
     */
188
    public function optimizeRTIndex(): void
189
    {
190
        foreach ($this->config['indexes'] as $index) {
191
            $this->helper->flushRtIndex($index);
192
            $this->helper->optimizeIndex($index);
193
        }
194
    }
195
196
    /**
197
     * @param string $rt_index (releases_rt or predb_rt)
198
     * @param string $searchString (what are we looking for?)
199
     * @param array $column (one or multiple columns from the columns that exist in indexes)
200
     * @param array $searchArray
201
     *
202
     * @return array
203
     * @throws \Foolz\SphinxQL\Exception\ConnectionException
204
     * @throws \Foolz\SphinxQL\Exception\DatabaseException
205
     * @throws \Foolz\SphinxQL\Exception\SphinxQLException
206
     */
207
    public function searchIndexes(string $rt_index, $searchString = '', $column = [], array $searchArray = []): array
208
    {
209
        $query = $this->sphinxQL->select()->from($rt_index)->option('max_matches', 10000)->option('ranker', 'sph04')->option('sort_method', 'pq')->limit(0, 10000)->orderBy('id', 'desc');
210
        if (! empty($searchArray)) {
211
            foreach ($searchArray as $key => $value) {
212
                $query->match($key, $value, true);
213
            }
214
        } elseif (! empty($searchString)) {
215
            $query->match($column, $searchString, true);
216
        } else {
217
            return [];
218
        }
219
220
        try {
221
            return $query->execute()->fetchAllAssoc() ?? [];
222
        } catch (SphinxQLException $exception) {
223
            return [];
224
        } catch (DatabaseException $databaseException) {
225
            return [];
226
        }
227
    }
228
}
229