Completed
Push — master ( 158640...6228b6 )
by Carlos
02:38 queued 01:15
created

src/Kernel/Traits/HasHttpRequests.php (2 issues)

Labels

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace EasyWeChat\Kernel\Traits;
13
14
use EasyWeChat\Kernel\Contracts\Arrayable;
15
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
16
use EasyWeChat\Kernel\Http\Response;
17
use EasyWeChat\Kernel\Support\Collection;
18
use GuzzleHttp\Client;
19
use GuzzleHttp\ClientInterface;
20
use GuzzleHttp\HandlerStack;
21
use Psr\Http\Message\ResponseInterface;
22
23
/**
24
 * Trait HasHttpRequests.
25
 *
26
 * @author overtrue <[email protected]>
27
 */
28
trait HasHttpRequests
29
{
30
    /**
31
     * @var \GuzzleHttp\ClientInterface
32
     */
33
    protected $httpClient;
34
35
    /**
36
     * @var array
37
     */
38
    protected $middlewares = [];
39
40
    /**
41
     * @var \GuzzleHttp\HandlerStack
42
     */
43
    protected $handlerStack;
44
45
    /**
46
     * @var array
47
     */
48
    protected static $defaults = [
49
        'curl' => [
50
            CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
51
        ],
52
    ];
53
54
    /**
55
     * Set guzzle default settings.
56
     *
57
     * @param array $defaults
58
     */
59
    public static function setDefaultOptions($defaults = [])
60
    {
61
        self::$defaults = $defaults;
62
    }
63
64
    /**
65
     * Return current guzzle default settings.
66
     *
67
     * @return array
68
     */
69
    public static function getDefaultOptions(): array
70
    {
71
        return self::$defaults;
72
    }
73
74
    /**
75
     * Set GuzzleHttp\Client.
76
     *
77
     * @param \GuzzleHttp\ClientInterface $httpClient
78
     *
79
     * @return $this
80
     */
81
    public function setHttpClient(ClientInterface $httpClient)
82
    {
83
        $this->httpClient = $httpClient;
84
85
        return $this;
86
    }
87
88
    /**
89
     * Return GuzzleHttp\Client instance.
90
     *
91
     * @return \GuzzleHttp\Client
92
     */
93
    public function getHttpClient(): Client
94
    {
95
        if (!($this->httpClient instanceof ClientInterface)) {
96
            $this->httpClient = new Client();
97
        }
98
99
        return $this->httpClient;
100
    }
101
102
    /**
103
     * Add a middleware.
104
     *
105
     * @param callable    $middleware
106
     * @param null|string $name
107
     *
108
     * @return $this
109
     */
110
    public function pushMiddleware(callable $middleware, string $name = null)
111
    {
112
        if (!is_null($name)) {
113
            $this->middlewares[$name] = $middleware;
114
        } else {
115
            array_push($this->middlewares, $middleware);
116
        }
117
118
        return $this;
119
    }
120
121
    /**
122
     * Return all middlewares.
123
     *
124
     * @return array
125
     */
126
    public function getMiddlewares(): array
127
    {
128
        return $this->middlewares;
129
    }
130
131
    /**
132
     * Make a request.
133
     *
134
     * @param string $url
135
     * @param string $method
136
     * @param array  $options
137
     *
138
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
139
     */
140
    public function request($url, $method = 'GET', $options = []): ResponseInterface
141
    {
142
        $method = strtoupper($method);
143
144
        $options = array_merge(self::$defaults, $options, ['handler' => $this->getHandlerStack()]);
145
146
        $options = $this->fixJsonIssue($options);
147
148
        if (property_exists($this, 'baseUri') && !is_null($this->baseUri)) {
149
            $options['base_uri'] = $this->baseUri;
0 ignored issues
show
The property baseUri does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
150
        }
151
152
        $response = $this->getHttpClient()->request($method, $url, $options);
153
        $response->getBody()->rewind();
154
155
        return $response;
156
    }
157
158
    /**
159
     * @param \GuzzleHttp\HandlerStack $handlerStack
160
     *
161
     * @return $this
162
     */
163
    public function setHandlerStack(HandlerStack $handlerStack)
164
    {
165
        $this->handlerStack = $handlerStack;
166
167
        return $this;
168
    }
169
170
    /**
171
     * Build a handler stack.
172
     *
173
     * @return \GuzzleHttp\HandlerStack
174
     */
175
    public function getHandlerStack(): HandlerStack
176
    {
177
        if ($this->handlerStack) {
178
            return $this->handlerStack;
179
        }
180
181
        $this->handlerStack = HandlerStack::create();
182
183
        foreach ($this->middlewares as $name => $middleware) {
184
            $this->handlerStack->push($middleware, $name);
185
        }
186
187
        return $this->handlerStack;
188
    }
189
190
    /**
191
     * @param \Psr\Http\Message\ResponseInterface $response
192
     * @param string|null                         $type
193
     *
194
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
195
     *
196
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
197
     */
198
    protected function resolveResponse(ResponseInterface $response, $type = null)
199
    {
200
        $response = Response::buildFromPsrResponse($response);
201
        $response->getBody()->rewind();
202
203
        switch ($type ?? 'array') {
204
            case 'collection':
205
                return $response->toCollection();
206
            case 'array':
207
                return $response->toArray();
208
            case 'object':
209
                return $response->toObject();
210
            case 'raw':
211
                return $response;
212
            default:
213
                if (!is_subclass_of($type, Arrayable::class)) {
0 ignored issues
show
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \EasyWeChat\Kernel\Contracts\Arrayable::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
214
                    throw new InvalidConfigException(sprintf('Config key "response_type" classname must be an instanceof %s', Arrayable::class));
215
                }
216
217
                return new $type($response);
218
        }
219
    }
220
221
    /**
222
     * @param mixed  $response
223
     * @param string $type
224
     *
225
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|string
226
     */
227
    protected function transformResponseToType($response, string $type)
228
    {
229
        if ($response instanceof ResponseInterface) {
230
            $response = Response::buildFromPsrResponse($response);
231
        } elseif (($response instanceof Collection) || is_array($response) || is_object($response)) {
232
            $response = new Response(200, [], json_encode($response));
233
        }
234
235
        return $this->resolveResponse($response, $type);
236
    }
237
238
    /**
239
     * @param array $options
240
     *
241
     * @return array
242
     */
243
    protected function fixJsonIssue(array $options): array
244
    {
245
        if (isset($options['json']) && is_array($options['json'])) {
246
            $options['headers'] = array_merge($options['headers'] ?? [], ['Content-Type' => 'application/json']);
247
248
            if (empty($options['json'])) {
249
                $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_FORCE_OBJECT);
250
            } else {
251
                $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_UNESCAPED_UNICODE);
252
            }
253
254
            unset($options['json']);
255
        }
256
257
        return $options;
258
    }
259
}
260