1
|
|
|
<?php |
2
|
|
|
namespace Elastica\Transport; |
3
|
|
|
|
4
|
|
|
use Elastica\Connection; |
5
|
|
|
use Elastica\Exception\Connection\GuzzleException; |
6
|
|
|
use Elastica\Exception\PartialShardFailureException; |
7
|
|
|
use Elastica\Exception\ResponseException; |
8
|
|
|
use Elastica\JSON; |
9
|
|
|
use Elastica\Request; |
10
|
|
|
use Elastica\Response; |
11
|
|
|
use Elastica\Util; |
12
|
|
|
use GuzzleHttp\Client; |
13
|
|
|
use GuzzleHttp\Exception\TransferException; |
14
|
|
|
use GuzzleHttp\Psr7; |
15
|
|
|
use GuzzleHttp\Psr7\Uri; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Elastica Guzzle Transport object. |
19
|
|
|
* |
20
|
|
|
* @author Milan Magudia <[email protected]> |
21
|
|
|
*/ |
22
|
|
|
class Guzzle extends AbstractTransport |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* Http scheme. |
26
|
|
|
* |
27
|
|
|
* @var string Http scheme |
28
|
|
|
*/ |
29
|
|
|
protected $_scheme = 'http'; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Curl resource to reuse. |
33
|
|
|
* |
34
|
|
|
* @var Client Guzzle client to reuse |
35
|
|
|
*/ |
36
|
|
|
protected static $_guzzleClientConnection; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Makes calls to the elasticsearch server. |
40
|
|
|
* |
41
|
|
|
* All calls that are made to the server are done through this function |
42
|
|
|
* |
43
|
|
|
* @param \Elastica\Request $request |
44
|
|
|
* @param array $params Host, Port, ... |
45
|
|
|
* |
46
|
|
|
* @throws \Elastica\Exception\ConnectionException |
47
|
|
|
* @throws \Elastica\Exception\ResponseException |
48
|
|
|
* @throws \Elastica\Exception\Connection\HttpException |
49
|
|
|
* |
50
|
|
|
* @return \Elastica\Response Response object |
51
|
|
|
*/ |
52
|
|
|
public function exec(Request $request, array $params) |
53
|
|
|
{ |
54
|
|
|
$connection = $this->getConnection(); |
55
|
|
|
|
56
|
|
|
$client = $this->_getGuzzleClient($this->_getBaseUrl($connection), $connection->isPersistent(), $request); |
57
|
|
|
|
58
|
|
|
$options = [ |
59
|
|
|
'exceptions' => false, // 4xx and 5xx is expected and NOT an exceptions in this context |
60
|
|
|
]; |
61
|
|
|
if ($connection->getTimeout()) { |
62
|
|
|
$options['timeout'] = $connection->getTimeout(); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
$proxy = $connection->getProxy(); |
66
|
|
|
|
67
|
|
|
// See: https://github.com/facebook/hhvm/issues/4875 |
68
|
|
View Code Duplication |
if (is_null($proxy) && defined('HHVM_VERSION')) { |
|
|
|
|
69
|
|
|
$proxy = getenv('http_proxy') ?: null; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
if (!is_null($proxy)) { |
73
|
|
|
$options['proxy'] = $proxy; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
$req = $this->_createPsr7Request($request, $connection); |
77
|
|
|
|
78
|
|
|
try { |
79
|
|
|
$start = microtime(true); |
80
|
|
|
$res = $client->send($req, $options); |
81
|
|
|
$end = microtime(true); |
82
|
|
|
} catch (TransferException $ex) { |
83
|
|
|
throw new GuzzleException($ex, $request, new Response($ex->getMessage())); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
$response = new Response((string) $res->getBody(), $res->getStatusCode()); |
87
|
|
|
$response->setQueryTime($end - $start); |
88
|
|
|
if ($connection->hasConfig('bigintConversion')) { |
89
|
|
|
$response->setJsonBigintConversion($connection->getConfig('bigintConversion')); |
|
|
|
|
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
$response->setTransferInfo( |
93
|
|
|
[ |
94
|
|
|
'request_header' => $request->getMethod(), |
95
|
|
|
'http_code' => $res->getStatusCode(), |
96
|
|
|
] |
97
|
|
|
); |
98
|
|
|
|
99
|
|
|
if ($response->hasError()) { |
100
|
|
|
throw new ResponseException($request, $response); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
if ($response->hasFailedShards()) { |
104
|
|
|
throw new PartialShardFailureException($request, $response); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
return $response; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @param Request $request |
112
|
|
|
* @param Connection $connection |
113
|
|
|
* |
114
|
|
|
* @return Psr7\Request |
115
|
|
|
*/ |
116
|
|
|
protected function _createPsr7Request(Request $request, Connection $connection) |
117
|
|
|
{ |
118
|
|
|
$req = new Psr7\Request( |
119
|
|
|
$request->getMethod(), |
120
|
|
|
$this->_getActionPath($request), |
121
|
|
|
$connection->hasConfig('headers') && is_array($connection->getConfig('headers')) |
122
|
|
|
? $connection->getConfig('headers') |
123
|
|
|
: [] |
124
|
|
|
); |
125
|
|
|
|
126
|
|
|
$data = $request->getData(); |
127
|
|
|
if (!empty($data) || '0' === $data) { |
128
|
|
|
if ($req->getMethod() == Request::GET) { |
129
|
|
|
$req = $req->withMethod(Request::POST); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
View Code Duplication |
if ($this->hasParam('postWithRequestBody') && $this->getParam('postWithRequestBody') == true) { |
|
|
|
|
133
|
|
|
$request->setMethod(Request::POST); |
134
|
|
|
$req = $req->withMethod(Request::POST); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
$req = $req->withBody( |
138
|
|
|
Psr7\stream_for(is_array($data) |
139
|
|
|
? JSON::stringify($data, JSON_UNESCAPED_UNICODE) |
140
|
|
|
: $data |
141
|
|
|
) |
142
|
|
|
); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return $req; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Return Guzzle resource. |
150
|
|
|
* |
151
|
|
|
* @param string $baseUrl |
152
|
|
|
* @param bool $persistent False if not persistent connection |
153
|
|
|
* @param Request $request Elastica Request Object |
154
|
|
|
* |
155
|
|
|
* @return Client |
156
|
|
|
*/ |
157
|
|
|
protected function _getGuzzleClient($baseUrl, $persistent = true, Request $request) |
158
|
|
|
{ |
159
|
|
|
if (!$persistent || !self::$_guzzleClientConnection) { |
160
|
|
|
self::$_guzzleClientConnection = new Client([ |
161
|
|
|
'base_uri' => $baseUrl, |
162
|
|
|
'headers' => [ |
163
|
|
|
'Content-Type' => $request->getContentType(), |
164
|
|
|
], |
165
|
|
|
]); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
return self::$_guzzleClientConnection; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Builds the base url for the guzzle connection. |
173
|
|
|
* |
174
|
|
|
* @param \Elastica\Connection $connection |
175
|
|
|
* |
176
|
|
|
* @return string |
177
|
|
|
*/ |
178
|
|
|
protected function _getBaseUrl(Connection $connection) |
179
|
|
|
{ |
180
|
|
|
// If url is set, url is taken. Otherwise port, host and path |
181
|
|
|
$url = $connection->hasConfig('url') ? $connection->getConfig('url') : ''; |
182
|
|
|
|
183
|
|
|
if (!empty($url)) { |
184
|
|
|
$baseUri = $url; |
185
|
|
|
} else { |
186
|
|
|
$baseUri = (string) Uri::fromParts([ |
187
|
|
|
'scheme' => $this->_scheme, |
188
|
|
|
'host' => $connection->getHost(), |
189
|
|
|
'port' => $connection->getPort(), |
190
|
|
|
'path' => ltrim('/', $connection->getPath()), |
191
|
|
|
]); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
return rtrim($baseUri, '/'); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Builds the action path url for each request. |
199
|
|
|
* |
200
|
|
|
* @param \Elastica\Request $request |
201
|
|
|
* |
202
|
|
|
* @return string |
203
|
|
|
*/ |
204
|
|
|
protected function _getActionPath(Request $request) |
205
|
|
|
{ |
206
|
|
|
$action = $request->getPath(); |
207
|
|
|
if ($action) { |
208
|
|
|
$action = '/'.ltrim($action, '/'); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
if (!Util::isDateMathEscaped($action)) { |
212
|
|
|
$action = Util::escapeDateMath($action); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
$query = $request->getQuery(); |
216
|
|
|
|
217
|
|
|
if (!empty($query)) { |
218
|
|
|
$action .= '?'.http_build_query( |
219
|
|
|
$this->sanityzeQueryStringBool($query) |
|
|
|
|
220
|
|
|
); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
return $action; |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.