Completed
Push — master ( 1bbf97...78576b )
by Mehmet
03:15
created

ElasticSearch::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 3
ccs 0
cts 1
cp 0
rs 10
cc 1
eloc 1
nc 1
nop 2
crap 2
1
<?php
2
3
namespace Soupmix;
4
/*
5
Elasticsearch Adapter
6
*/
7
Use Elasticsearch\Client;
8
9
class ElasticSearch implements Base
10
{
11
    protected $conn = null;
12
    private $index = null;
13
14
    private static $operators = [
15
        'range'     => ['gt', 'gte', 'lt', 'lte'],
16
        'standart'  => ['prefix', 'regexp', 'wildchard'],
17
        'BooleanQueryLevel' => ['not'],
18
        'special'   => ['in']
19
    ];
20
21
22 3
    public function __construct($config, Client $client)
23
    {
24 3
        $this->index = $config['db_name'];
25 3
        $this->conn = $client;
26 3
    }
27
28 3
29
    public function getConnection()
30 3
    {
31 3
        return $this->conn;
32
    }
33
34
    public function create($collection, $fields)
35
    {
36
    }
37 3
    public function drop($collection)
38
    {
39 3
        $params = ['index' => $this->index];
40
        try {
41 3
            $this->conn->indices()->delete($params);
42 3
        } catch (\Exception $e) {
43
            // This ignore the error
44 1
            return false;
45
        }
46 2
        return true;
47
    }
48
49
    public function truncate($collection)
50
    {
51
    }
52
53
    public function createIndexes($collection, $indexes)
54
    {
55
    }
56
57 2
    public function insert($collection, $values)
58
    {
59 2
        $params = [];
60 2
        $params['body'] = $values;
61 2
        $params['index'] = $this->index;
62 2
        $params['type'] = $collection;
63
        try {
64 2
            $result = $this->conn->index($params);
65 2
            if ($result['created']) {
66 2
                return $result['_id'];
67
            }
68
            return null;
69
        } catch (\Exception $e) {
70
            return;
71
        }
72
    }
73
74 1
    public function get($collection, $docId)
75
    {
76 1
        $params = [];
77 1
        $params['index'] = $this->index;
78 1
        $params['type'] = $collection;
79
80
        try {
81 1
            if (gettype($docId) == "array") {
82
                $params['body'] = [
83
                    'query' => [
84
                        'filtered' => [
85
                            'filter' => [
86
                                'ids' => ['values'=>$docId]
87
                            ],
88
                        ],
89
                    ],
90
                ];
91
                $results = $this->conn->search($params);
92
                if ($results['hits']['total'] == 0) {
93
                    return;
94
                }
95
                $result = [];
96
                foreach ($results['hits']['hits'] as $item){
97
                    $result[$item['_id']]=$item['_source'];
98
                }
99
                return $result;
100
            } else {
101 1
                $params['id'] = $docId;
102 1
                $result = $this->conn->get($params);
103
            }
104 1
            if ($result['found']) {
105 1
                $result['_source']['_id'] = $result['_id'];
106 1
                return $result['_source'];
107
            } else {
108
                return;
109
            }
110
        } catch (\Exception $e) {
111
            return;
112
        }
113
    }
114
115
    public function update($collection, $filter, $values)
116
    {
117
        $docs = $this->find($collection, $filter, ['_id']);
118
        if ($docs['total']===0) {
119
            return 0;
120
        }
121
        $params = [];
122
        $params['index'] = $this->index;
123
        $params['type'] = $collection;
124
        $modified_count = 0;
125
        foreach ($docs['data'] as $doc) {
126
            $params['id'] = $doc['_id'];
127
            $params['body']['doc'] = $values;
128
            try {
129
                $return = $this->conn->update($params);
130
                if ($return['_shards']['successful']==1) {
131
                    ++$modified_count;
132
                }
133
            } catch (\Exception $e) {
134
                // should we throw exception? Probably not.
135
            }
136
        }
137
138
        return $modified_count;
139
    }
140
141 2
    public function delete($collection, $filter)
142
    {
143 2
        if (isset($filter['_id'])) {
144 2
            $params = [];
145 2
            $params['index'] = $this->index;
146 2
            $params['type'] = $collection;
147 2
            $params['id'] = $filter['_id'];
148
            try {
149 2
                $result = $this->conn->delete($params);
150 2
            } catch (\Exception $e) {
151
                return 0;
152
            }
153 2
            if ($result['found']) {
154 2
                return 1;
155
            }
156
        } else {
157
            $params = [];
158
            $params['index'] = $this->index;
159
            $params['type'] = $collection;
160
            $params['fields'] = '_id';
161
            $result = $this->find($collection, $filter, ['_id'], null, 0, 1);
162
            if ($result['total']==1) {
163
                $params = [];
164
                $params['index'] = $this->index;
165
                $params['type'] = $collection;
166
                $params['id'] = $result['data']['_id'];
167
                try {
168
                    $result = $this->conn->delete($params);
169
                } catch (\Exception $e) {
170
                    return 0;
171
                }
172
                if ($result['found']) {
173
                    return 1;
174
                }
175
            }
176
        }
177
178
        return 0;
179
    }
180
181 1
    public function find($collection, $filters, $fields = null, $sort = null, $start = 0, $limit = 25, $debug = false)
182
    {
183 1
        $return_type = '_source';
184 1
        $params = [];
185 1
        $params['index'] = $this->index;
186 1
        $params['type'] = $collection;
187 1
        if ($filters!==null) {
188 1
            $filters = self::buildFilter($filters);
189 1
            $params['body'] = [
190
                'query' => [
191
                    'filtered' => [
192
                        'filter' => [
193 1
                            'bool' => $filters,
194 1
                        ],
195 1
                    ],
196 1
                ],
197
            ];
198 1
        }
199 1
        $count = $this->conn->count($params);
200 1
        if ($fields!==null) {
201
            $params['fields'] = implode(',', $fields);
202
            $return_type = 'fields';
203
        }
204 1
        if ($sort!==null) {
205
            $params['sort'] = '';
206
            foreach ($sort as $sort_key => $sort_dir) {
207
                if ($params['sort']!='') {
208
                    $params['sort'] .= ',';
209
                }
210
                $params['sort'] .= $sort_key.':'.$sort_dir;
211
            }
212
        }
213 1
        if ($fields != null) {
214
            $params['fields'] = $fields;
215
            $return_type = 'fields';
216
        }
217 1
        $params['from'] = (int) $start;
218 1
        $params['size'] = (int) $limit;
219 1
        if ($debug) {
220
           return $params;
221
        }
222 1
        $return = $this->conn->search($params);
223 1
        if ($return['hits']['total']==0) {
224
            return ['total' => 0, 'data' => null];
225
        }
226 1
        elseif ($limit==1) {
227
            $return['hits']['hits'][0][$return_type]['_id'] = $return['hits']['hits'][0]['_id'];
228
            return ['total' => 1, 'data' => $return['hits']['hits'][0][$return_type]];
229
        }
230 1
        $result = [];
231 1
        foreach ($return['hits']['hits'] as $item) {
232 1
            if (($return_type == 'fields') && ($fields != ['_id'])) {
233
                foreach ($item[$return_type]as $k => $v) {
234
                    $item[$return_type][$k] = $v[0];
235
                }
236
            }
237 1
            $item[$return_type]['_id'] = $item['_id'];
238 1
            $result[] = $item[$return_type];
239 1
        }
240 1
        return ['total' => $count['count'], 'data' => $result];
241
    }
242
243
    public function query($collection)
244
    {
245
        return new ElasticSearchQueryBuilder($collection);
246
    }
247
248 1
    public static function buildFilter($filter)
249
    {
250 1
        $filters = [];
251 1
        foreach ($filter as $key => $value) {
252 1
            $is_not = '';
253 1
            if (strpos($key, '__')!==false) {
254 1
                $tmpFilters = self::buildFilterForKeys($key, $value, $is_not);
255 1
                $filters = self::mergeFilters($filters, $tmpFilters);
256 1
            } elseif ((strpos($key, '__') === false) && (is_array($value))) {
257 1
                $filters['should'] = self::buildFilterForOR($value);
258 1
            } else {
259 1
                $filters['must'][] = ['term' => [$key => $value]];
260
            }
261 1
        }
262 1
        return $filters;
263
    }
264
265 1
    private static function mergeFilters ($filters, $tmpFilters){
266 1
        foreach ($tmpFilters as $fKey => $fVals) {
267 1
            if (isset($filters[$fKey])) {
268 1
                foreach ($fVals as $fVal) {
269 1
                    $filters[$fKey][] = $fVal;
270 1
                }
271 1
            } else {
272 1
                $filters[$fKey] = $fVals;
273
            }
274 1
        }
275 1
        return $filters;
276
    }
277
278 1
    private static function buildFilterForKeys($key, $value, $is_not)
279
    {
280 1
        $filters = [];
281 1
        preg_match('/__(.*?)$/i', $key, $matches);
282 1
        $operator = $matches[1];
283 1
        if (strpos($operator, '!')===0) {
284
            $operator = str_replace('!', '', $operator);
285
            $is_not = '_not';
286
        }
287 1
        $key = str_replace($matches[0], '', $key);
288 1
        foreach (self::$operators as $type => $possibilities) {
289 1
            if (in_array($operator, $possibilities)) {
290
                switch ($type) {
291 1
                    case 'range':
292 1
                        $filters['must'.$is_not][] = ['range' => [$key => [$operator => $value]]];
293 1
                        break;
294
                    case 'standart':
295
                        $filters['must'.$is_not][] = [$type => [$key => $value]];
296
                        break;
297
                    case 'BooleanQueryLevel':
298
                        switch ($operator) {
299
                            case 'not':
300
                                $filters['must_not'][] = ['term' => [$key => $value]];
301
                                break;
302
                        }
303
                        break;
304
                    case 'special':
305
                        switch ($operator) {
306
                            case 'in':
307
                                $filters['must'.$is_not][] = ['terms' => [$key => $value]];
308
                                break;
309
                        }
310
                        break;
311
                }
312 1
            }
313 1
        }
314 1
        return $filters;
315
    }
316
317 1
    private static function buildFilterForOR($orValues)
318
    {
319 1
        $filters = [];
320 1
        foreach ($orValues as $orValue) {
321 1
            $subKey = array_keys($orValue)[0];
322 1
            $subValue = $orValue[$subKey];
323 1
            if (strpos($subKey, '__') !== false) {
324 1
                preg_match('/__(.*?)$/i', $subKey, $subMatches);
325 1
                $subOperator = $subMatches[1];
326 1
                if (strpos($subOperator, '!')===0) {
327
                    $subOperator = str_replace('!', '', $subOperator);
328
                }
329 1
                $subKey = str_replace($subMatches[0], '', $subKey);
330 1
                foreach (self::$operators as $type => $possibilities) {
331 1
                    if (in_array($subOperator, $possibilities)) {
332
                        switch ($type) {
333 1
                            case 'range':
334 1
                                $filters[] = ['range' => [$subKey => [$subOperator => $subValue]]];
335 1
                                break;
336
                            case 'standart':
337
                                $filters[] = [$type => [$subKey => $subValue]];
338
                                break;
339
                            case 'special':
340
                                switch ($subOperator) {
341
                                    case 'in':
342
                                        $filters[] = ['terms' => [$subKey => $subValue]];
343
                                        break;
344
                                }
345
                                break;
346
                        }
347 1
                    }
348 1
                }
349 1
            } else {
350
                $filters[] = ['term' => [$subKey => $subValue]];
351
            }
352 1
        }
353 1
        return $filters;
354
    }
355
}
356