Completed
Push — devel ( 9c998f...29233a )
by Alexey
05:42
created

Query::addListener()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Bardex\Elastic;
4
5
6
use Elasticsearch\Client as ElasticClient;
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\NullLogger;
9
10
/**
11
 * Class Query
12
 * @package Bardex\Elastic
13
 * @author Alexey Sumin <[email protected]>
14
 */
15
abstract class Query implements \JsonSerializable
16
{
17
    /**
18
     * @var ElasticClient $client
19
     */
20
    protected $elastic;
21
22
    /**
23
     * @var array
24
     */
25
    protected $listeners = [];
26
27
    /**
28
     * Получить собранный elasticsearch-запрос
29
     * @return array
30
     */
31
    abstract public function getQuery();
32
33
34
    /**
35
     * Отправить запрос на конкретный endpoint elasticsearch-сервера
36
     * @param array $query
37
     * @return array
38
     */
39
    abstract protected function executeQuery(array $query);
40
41
42
    /**
43
     * Конструктор
44
     * @param ElasticClient $elastic
45
     */
46
    public function __construct(ElasticClient $elastic)
47
    {
48
        $this->elastic = $elastic;
49
    }
50
51
52
    /**
53
     * Выполнить запрос к ES и вернуть результаты поиска.
54
     * @return SearchResult - возвращает набор документов
55
     */
56
    public function fetchAll()
57
    {
58
        $response = $this->fetchRaw();
59
        $result = $this->createSearchResult($response);
60
        return $result;
61
    }
62
63
64
    /**
65
     * Выполнить запрос к ES и вернуть необработанный результат (с мета-данными).
66
     * @return array возвращает необработанный ответ ES
67
     */
68
    public function fetchRaw()
69
    {
70
        // build query
71
        $query = $this->getQuery();
72
73
        // send query to elastic
74
        $start  = microtime(1);
75
76
        try {
77
            $result = $this->executeQuery($query);
78
            $time   = round((microtime(1) - $start) * 1000);
79
            $this->triggerSuccess($query, $result, $time);
80
            return $result;
81
        }
82
        catch (\Exception $e) {
83
            $this->triggerError($query, $e);
84
            throw $e;
85
        }
86
    }
87
88
89
    /**
90
     * Создать из ответа ES-сервера экземляр SearchResult
91
     * @param array $response
92
     * @return SearchResult
93
     */
94
    protected function createSearchResult(array $response)
95
    {
96
        $results  = $this->extractDocuments($response);
97
        $total    = $this->extractTotal($response);
98
        $searchResult = new SearchResult($results, $total);
99
        return $searchResult;
100
    }
101
102
    /**
103
     * Выбрать документы из ответа ES-сервера и добавить script fields.
104
     * @param array $response - ответ ES сервера.
105
     * @return array - возвращает набор документов
106
     */
107
    protected function extractDocuments(array $response)
108
    {
109
        $results = [];
110
        if (isset($response['hits']['hits'])) {
111
            foreach ($response['hits']['hits'] as $hit) {
112
                $row = $hit['_source'];
113
                if (isset($hit['fields'])) { // script fields
114
                    foreach ($hit['fields'] as $field => $data) {
115
                        if (count($data) == 1) {
116
                            $row[$field] = array_shift($data);
117
                        } else {
118
                            $row[$field] = $data;
119
                        }
120
                    }
121
                }
122
                $results[] = $row;
123
            }
124
        }
125
        return $results;
126
    }
127
128
129
    /**
130
     * Выбрать из ответа ES-сервера количество найденных документов.
131
     * @param array $response - ответ ES сервера.
132
     * @return integer - возвращает количество найденных документов.
133
     */
134
    protected function extractTotal(array $response)
135
    {
136
        $total = 0;
137
        if (isset($response['hits']['total'])) {
138
            $total = $response['hits']['total'];
139
        }
140
        return $total;
141
    }
142
143
    public function addListener(IListener $listener)
144
    {
145
        $this->listeners[] = $listener;
146
        return $this;
147
    }
148
149
    public function removeListener(IListener $listener)
150
    {
151
        foreach ($this->listeners as $i => $listItem) {
152
            if ($listener === $listItem) {
153
                unset($this->listeners[$i]);
154
            }
155
        }
156
        return $this;
157
    }
158
159
    protected function triggerSuccess(array $query, array $response, $time)
160
    {
161
        foreach ($this->listeners as $listener) {
162
            $listener->onSuccess($query, $response, $time);
163
        }
164
    }
165
166
    protected function triggerError(array $query, \Exception $e)
167
    {
168
        foreach ($this->listeners as $listener) {
169
            $listener->onError($query, $e);
170
        }
171
    }
172
173
    /**
174
     * Имплементация \JsonSerializable
175
     * @return array
176
     */
177
    public function jsonSerialize()
178
    {
179
        return $this->getQuery();
180
    }
181
}