Completed
Push — master ( 8a6a3b...86b2ed )
by Nicolas
03:28
created

Guzzle::_createPsr7Request()   B

Complexity

Conditions 9
Paths 5

Size

Total Lines 31

Duplication

Lines 4
Ratio 12.9 %

Importance

Changes 0
Metric Value
dl 4
loc 31
rs 8.0555
c 0
b 0
f 0
cc 9
nc 5
nop 2
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')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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'));
0 ignored issues
show
Documentation introduced by
$connection->getConfig('bigintConversion') is of type array|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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)
0 ignored issues
show
Documentation introduced by
$query is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
220
                );
221
        }
222
223
        return $action;
224
    }
225
}
226