<?php
* This file is part of the overtrue/wechat.
*
* (c) overtrue <i@overtrue.me>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace EasyWeChat\Kernel;
use EasyWeChat\Kernel\Contracts\AccessTokenInterface;
use EasyWeChat\Kernel\Http\Response;
use EasyWeChat\Kernel\Traits\HasHttpRequests;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LogLevel;
* Class BaseClient.
*
* @author overtrue <i@overtrue.me>
*/
class BaseClient
{
use HasHttpRequests {
request as performRequest;
}
* @var \EasyWeChat\Kernel\ServiceContainer
*/
protected $app;
* @var \EasyWeChat\Kernel\Contracts\AccessTokenInterface|null
*/
protected $accessToken = null;
* @var string
*/
protected $baseUri;
* BaseClient constructor.
*
* @param \EasyWeChat\Kernel\ServiceContainer $app
* @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface|null $accessToken
*/
public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null)
{
$this->app = $app;
$this->accessToken = isset($accessToken) ? $accessToken : $this->app['access_token'];
}
* GET request.
*
* @param $url
* @param array $query
*
* @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function httpGet($url, array $query = [])
{
return $this->request($url, 'GET', ['query' => $query]);
}
* POST request.
*
* @param $url
* @param array $data
*
* @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function httpPost($url, array $data = [])
{
return $this->request($url, 'POST', ['form_params' => $data]);
}
* JSON request.
*
* @param $url
* @param array $data
* @param array $query
*
* @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function httpPostJson($url, array $data = [], array $query = [])
{
return $this->request($url, 'POST', ['query' => $query, 'json' => $data]);
}
* Upload file.
*
* @param $url
* @param array $files
* @param array $form
* @param array $query
*
* @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function httpUpload($url, array $files = [], array $form = [], array $query = [])
{
$multipart = [];
foreach ($files as $name => $path) {
$multipart[] = ['name' => $name, 'contents' => fopen($path, 'r')];
}
foreach ($form as $name => $contents) {
$multipart[] = compact('name', 'contents');
}
return $this->request($url, 'POST', ['query' => $query, 'multipart' => $multipart, 'connect_timeout' => 30, 'timeout' => 30, 'read_timeout' => 30]);
}
* @return AccessTokenInterface
*/
public function getAccessToken()
{
return $this->accessToken;
}
* @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface $accessToken
*
* @return $this
*/
public function setAccessToken(AccessTokenInterface $accessToken)
{
$this->accessToken = $accessToken;
return $this;
}
* @param $url
* @param $method
* @param array $options
* @param bool $returnRaw
*
* @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function request($url, $method = 'GET', array $options = [], $returnRaw = false)
{
if (empty($this->middlewares)) {
$this->registerHttpMiddlewares();
}
$response = $this->performRequest($url, $method, $options);
return $returnRaw ? $response : $this->castResponseToType($response, $this->app->config->get('response_type'));
}
* @param $url
* @param $method
* @param array $options
*
* @return \EasyWeChat\Kernel\Http\Response
*
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function requestRaw($url, $method = 'GET', array $options = [])
{
return Response::buildFromPsrResponse($this->request($url, $method, $options, true));
}
* Register Guzzle middlewares.
*/
protected function registerHttpMiddlewares()
{
$this->pushMiddleware($this->retryMiddleware(), 'retry');
$this->pushMiddleware($this->accessTokenMiddleware(), 'access_token');
$this->pushMiddleware($this->logMiddleware(), 'log');
}
* Attache access token to request query.
*
* @return \Closure
*/
protected function accessTokenMiddleware()
{
return function (callable $handler) {
return function (RequestInterface $request, array $options) use($handler) {
if ($this->accessToken) {
$request = $this->accessToken->applyToRequest($request, $options);
}
return $handler($request, $options);
};
};
}
* Log the request.
*
* @return \Closure
*/
protected function logMiddleware()
{
$formatter = new MessageFormatter(!empty($this->app['config']['http.log_template']) ? $this->app['config']['http.log_template'] : MessageFormatter::DEBUG);
return Middleware::log($this->app['logger'], $formatter, LogLevel::DEBUG);
}
* Return retry middleware.
*
* @return \Closure
*/
protected function retryMiddleware()
{
return Middleware::retry(function ($retries, RequestInterface $request, ResponseInterface $response = null) {
if ($retries < $this->app->config->get('http.max_retries', 1) && $response && ($body = $response->getBody())) {
$response = json_decode($body, true);
if (!empty($response['errcode']) && in_array(abs($response['errcode']), [40001, 40014, 42001], true)) {
$this->accessToken->refresh();
$this->app['logger']->debug('Retrying with refreshed access token.');
return true;
}
}
return false;
}, function () {
return abs($this->app->config->get('http.retry_delay', 500));
});
}
}