From baf7089614f086d671966bc8d72b7adc25f17285 Mon Sep 17 00:00:00 2001 From: Pe Ell Date: Mon, 22 May 2017 07:18:24 +0300 Subject: [PATCH] Extract Http Client from Rest Client (#20) Extract HttpClient from Rest Client --- CHANGELOG.md | 4 + README.md | 21 ++-- examples/cookie-authorization.php | 20 ++-- examples/token-authorization.php | 16 ++- .../Exceptions/AuthenticationException.php | 4 +- .../Exceptions/AuthorizationException.php | 4 +- src/Client/Contracts/Client.php | 42 +++++-- src/Client/Exceptions/ClientException.php | 26 +++++ src/Client/YouTrackClient.php | 91 +++++++++------ src/HttpClient/Contracts/HttpClient.php | 36 ++++++ .../Exceptions/HttpClientException.php | 26 +++++ src/HttpClient/GuzzleHttpClient.php | 108 ++++++++++++++++++ .../Authenticator/CookieAuthorizerTest.php | 9 +- .../Authenticator/TokenAuthorizerTest.php | 5 +- 14 files changed, 335 insertions(+), 77 deletions(-) create mode 100644 src/Client/Exceptions/ClientException.php create mode 100644 src/HttpClient/Contracts/HttpClient.php create mode 100644 src/HttpClient/Exceptions/HttpClientException.php create mode 100644 src/HttpClient/GuzzleHttpClient.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 55fbea0..3e48ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to `youtrack-rest-php` will be documented in this file. ### Added - `Authenticator` contract and `CookieAuthenticator` implementation. +- `HttpClient` contract and `GuzzleHttpClient` implementation. - `isStatusCode` assert in `Response` contract. ### Updated @@ -14,9 +15,12 @@ All notable changes to `youtrack-rest-php` will be documented in this file. - `CookieAuthorizer` constructor accepts `Authenticator` instead of credentials. - `TokenAuthorizer` constructor accepts string token instead of array. - `Authorizer` delegates authentication to `Authenticator`. +- `Client` delegates HTTP requests to `HttpClient`. - Changed namespace of `AuthenticationException`. - `getHeaders` method was dropped from `Authorizer` contract. - `Response` interface methods `getResponse`, `getStatusCode`, `getCookie`, `getLocation` were renamed to `httpResponse`, `statusCode`, `cookie`, `location` respectively. +- `User-Agent` header is more verbose. +- REST Client version is defined in `Client` contract instead of each concrete implementation. ## [2.0.1] - 2017-05-21 diff --git a/README.md b/README.md index 835b626..312f6ed 100644 --- a/README.md +++ b/README.md @@ -99,26 +99,32 @@ require_once '/path/to/your-project/vendor/autoload.php'; Starting with YouTrack 2017.1 release [authorization based on permanent tokens](https://www.jetbrains.com/help/youtrack/standalone/2017.2/Manage-Permanent-Token.html) is recommended as the main approach for the authorization in your REST API calls. ```php -// Instantiate HTTP Client -$http = new \GuzzleHttp\Client([ +// Instantiate PSR-7 HTTP Client +$psrHttpClient = new \GuzzleHttp\Client([ 'base_uri' => 'https://example.com', ]); +// Instantiate YouTrack API HTTP Client +$httpClient = new \Cog\YouTrack\Rest\HttpClient\GuzzleHttpClient($psrHttpClient); + // Instantiate YouTrack API Token Authorizer $authorizer = new \Cog\YouTrack\Rest\Authorizer\TokenAuthorizer('YOUTRACK_API_TOKEN'); // Instantiate YouTrack API Client -$youtrack = new \Cog\YouTrack\Rest\YouTrackClient($http, $authorizer); +$youtrack = new \Cog\YouTrack\Rest\YouTrackClient($httpClient, $authorizer); ``` #### Cookie authorization ```php -// Instantiate HTTP Client -$http = new \GuzzleHttp\Client([ +// Instantiate PSR-7 HTTP Client +$psrHttpClient = new \GuzzleHttp\Client([ 'base_uri' => 'https://example.com', ]); +// Instantiate YouTrack API HTTP Client +$httpClient = new \Cog\YouTrack\Rest\HttpClient\GuzzleHttpClient($psrHttpClient); + // Instantiate YouTrack API Cookie Authenticator $authenticator = new \Cog\YouTrack\Rest\Authenticator\CookieAuthenticator('YOUTRACK_USERNAME', 'YOUTRACK_PASSWORD'); @@ -126,12 +132,11 @@ $authenticator = new \Cog\YouTrack\Rest\Authenticator\CookieAuthenticator('YOUTR $authorizer = new \Cog\YouTrack\Rest\Authorizer\CookieAuthorizer($authenticator); // Instantiate YouTrack API Client -$youtrack = new \Cog\YouTrack\Rest\YouTrackClient($http, $authorizer); +$youtrack = new \Cog\YouTrack\Rest\YouTrackClient($httpClient, $authorizer); ``` ### API requests - #### HTTP GET request ```php @@ -153,7 +158,7 @@ $response = $youtrack->post('/issue', [ ```php $response = $youtrack->put('/issue/TEST-1', [ 'summary' => 'Updated summary', - 'description' => Updated description, + 'description' => 'Updated description', ]); ``` diff --git a/examples/cookie-authorization.php b/examples/cookie-authorization.php index 9ab60f0..1aba8a5 100644 --- a/examples/cookie-authorization.php +++ b/examples/cookie-authorization.php @@ -14,24 +14,30 @@ // Boot third party libraries require_once __DIR__ . '/../vendor/autoload.php'; +use Cog\YouTrack\Rest; + // Application configuration (replace with your YouTrack server values) $apiBaseUri = 'https://write-youtrack-domain.here'; -$apiUsername = 'YOUR_USERNAME'; -$apiPassword = 'YOUR_PASSWORD'; +$apiUsername = 'YOUTRACK_USERNAME'; +$apiPassword = 'YOUTRACK_PASSWORD'; -// Instantiate HTTP Client -$http = new \GuzzleHttp\Client([ +// Instantiate PSR-7 HTTP Client +$psrHttpClient = new \GuzzleHttp\Client([ 'base_uri' => $apiBaseUri, + 'debug' => true, ]); +// Instantiate YouTrack API HTTP Client +$httpClient = new Rest\HttpClient\GuzzleHttpClient($psrHttpClient); + // Instantiate YouTrack API Cookie Authenticator -$authenticator = new \Cog\YouTrack\Rest\Authenticator\CookieAuthenticator($apiUsername, $apiPassword); +$authenticator = new Rest\Authenticator\CookieAuthenticator($apiUsername, $apiPassword); // Instantiate YouTrack API Cookie Authorizer -$authorizer = new \Cog\YouTrack\Rest\Authorizer\CookieAuthorizer($authenticator); +$authorizer = new Rest\Authorizer\CookieAuthorizer($authenticator); // Instantiate YouTrack API Client -$client = new \Cog\YouTrack\Rest\Client\YouTrackClient($http, $authorizer); +$client = new Rest\Client\YouTrackClient($httpClient, $authorizer); // Do request to the API $response = $client->get('/admin/project'); diff --git a/examples/token-authorization.php b/examples/token-authorization.php index 7d9e987..6d9ee7f 100644 --- a/examples/token-authorization.php +++ b/examples/token-authorization.php @@ -14,20 +14,26 @@ // Boot third party libraries require_once __DIR__ . '/../vendor/autoload.php'; +use Cog\YouTrack\Rest; + // Application configuration (replace with your YouTrack server values) $apiBaseUri = 'https://write-youtrack-domain.here'; -$apiAuthToken = 'WRITE_YOUR_TOKEN_HERE'; +$apiToken = 'YOUTRACK_PERMANENT_TOKEN'; -// Instantiate HTTP Client -$http = new \GuzzleHttp\Client([ +// Instantiate PSR-7 HTTP Client +$psrHttpClient = new \GuzzleHttp\Client([ 'base_uri' => $apiBaseUri, + 'debug' => true, ]); +// Instantiate YouTrack API HTTP Client +$httpClient = new Rest\HttpClient\GuzzleHttpClient($psrHttpClient); + // Instantiate YouTrack API Token Authorizer -$authorizer = new \Cog\YouTrack\Rest\Authorizer\TokenAuthorizer($apiAuthToken); +$authorizer = new Rest\Authorizer\TokenAuthorizer($apiToken); // Instantiate YouTrack API Client -$client = new \Cog\YouTrack\Rest\Client\YouTrackClient($http, $authorizer); +$client = new Rest\Client\YouTrackClient($httpClient, $authorizer); // Do request to the API $response = $client->get('/admin/project'); diff --git a/src/Authenticator/Exceptions/AuthenticationException.php b/src/Authenticator/Exceptions/AuthenticationException.php index 4f62b88..f47bb86 100644 --- a/src/Authenticator/Exceptions/AuthenticationException.php +++ b/src/Authenticator/Exceptions/AuthenticationException.php @@ -13,14 +13,14 @@ namespace Cog\YouTrack\Rest\Authenticator\Exceptions; -use Cog\YouTrack\Rest\Authorizer\Exceptions\AuthorizationException; +use Cog\YouTrack\Rest\Client\Exceptions\ClientException; /** * Class AuthenticationException. * * @package Cog\YouTrack\Rest\Authenticator\Exceptions */ -class AuthenticationException extends AuthorizationException +class AuthenticationException extends ClientException { // } diff --git a/src/Authorizer/Exceptions/AuthorizationException.php b/src/Authorizer/Exceptions/AuthorizationException.php index 1b0892b..ceb7576 100644 --- a/src/Authorizer/Exceptions/AuthorizationException.php +++ b/src/Authorizer/Exceptions/AuthorizationException.php @@ -13,14 +13,14 @@ namespace Cog\YouTrack\Rest\Authorizer\Exceptions; -use Exception; +use Cog\YouTrack\Rest\Client\Exceptions\ClientException; /** * Class AuthorizationException. * * @package Cog\YouTrack\Rest\Authorizer\Exceptions */ -class AuthorizationException extends Exception +class AuthorizationException extends ClientException { // } diff --git a/src/Client/Contracts/Client.php b/src/Client/Contracts/Client.php index 6dc2aa6..365dcb0 100644 --- a/src/Client/Contracts/Client.php +++ b/src/Client/Contracts/Client.php @@ -22,54 +22,76 @@ */ interface Client { + /** + * Version of YouTrack REST PHP client. + */ + const VERSION = '3.0.0'; + /** * Create and send an HTTP request. * * @param string $method * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response * * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function request(string $method, string $uri, array $formData = []) : ResponseContract; + public function request(string $method, string $uri, array $options = []) : ResponseContract; /** * Create and send an GET HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function get(string $uri, array $formData = []): ResponseContract; + public function get(string $uri, array $options = []): ResponseContract; /** * Create and send an POST HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function post(string $uri, array $formData = []): ResponseContract; + public function post(string $uri, array $options = []): ResponseContract; /** * Create and send an PUT HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function put(string $uri, array $formData = []): ResponseContract; + public function put(string $uri, array $options = []): ResponseContract; /** * Create and send an DELETE HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function delete(string $uri, array $formData = []): ResponseContract; + public function delete(string $uri, array $options = []): ResponseContract; /** * Write header value. diff --git a/src/Client/Exceptions/ClientException.php b/src/Client/Exceptions/ClientException.php new file mode 100644 index 0000000..3bb2b3f --- /dev/null +++ b/src/Client/Exceptions/ClientException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\YouTrack\Rest\Client\Exceptions; + +use Exception; + +/** + * Class ClientException. + * + * @package Cog\YouTrack\Rest\Client\Exceptions + */ +class ClientException extends Exception +{ + // +} diff --git a/src/Client/YouTrackClient.php b/src/Client/YouTrackClient.php index c54225f..2fc978a 100644 --- a/src/Client/YouTrackClient.php +++ b/src/Client/YouTrackClient.php @@ -17,10 +17,11 @@ use Cog\YouTrack\Rest\Authorizer\Contracts\Authorizer as AuthorizerContract; use Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException; use Cog\YouTrack\Rest\Client\Contracts\Client as RestClientContract; +use Cog\YouTrack\Rest\Client\Exceptions\ClientException; +use Cog\YouTrack\Rest\HttpClient\Contracts\HttpClient as HttpClientContract; +use Cog\YouTrack\Rest\HttpClient\Exceptions\HttpClientException; use Cog\YouTrack\Rest\Response\Contracts\Response as ResponseContract; use Cog\YouTrack\Rest\Response\YouTrackResponse; -use GuzzleHttp\ClientInterface as GuzzleClientContract; -use GuzzleHttp\Exception\ClientException; /** * Class YouTrackRestClient. @@ -31,17 +32,12 @@ */ class YouTrackClient implements RestClientContract { - /** - * Version of YouTrack REST PHP client. - */ - const CLIENT_VERSION = '3.0.0'; - /** * HTTP Client. * - * @var \GuzzleHttp\ClientInterface + * @var \Cog\YouTrack\Rest\HttpClient\Contracts\HttpClient */ - private $http; + private $httpClient; /** * Authorization driver. @@ -70,12 +66,12 @@ class YouTrackClient implements RestClientContract /** * YouTrackClient constructor. * - * @param \GuzzleHttp\ClientInterface $http + * @param \Cog\YouTrack\Rest\HttpClient\Contracts\HttpClient $httpClient * @param \Cog\YouTrack\Rest\Authorizer\Contracts\Authorizer $authorizer */ - public function __construct(GuzzleClientContract $http, AuthorizerContract $authorizer) + public function __construct(HttpClientContract $httpClient, AuthorizerContract $authorizer) { - $this->http = $http; + $this->httpClient = $httpClient; $this->authorizer = $authorizer; } @@ -84,79 +80,96 @@ public function __construct(GuzzleClientContract $http, AuthorizerContract $auth * * @param string $method * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response * * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function request(string $method, string $uri, array $formData = []) : ResponseContract + public function request(string $method, string $uri, array $options = []) : ResponseContract { try { - $response = $this->http->request($method, $this->buildUri($uri), $this->buildOptions($formData)); - - return new YouTrackResponse($response); - } catch (ClientException $e) { + $response = $this->httpClient->request($method, $this->buildUri($uri), $this->buildOptions($options)); + } catch (HttpClientException $e) { switch ($e->getCode()) { case 401: - throw new InvalidTokenException($e->getMessage()); + throw new InvalidTokenException($e->getMessage(), $e->getCode()); break; case 403: - throw new AuthenticationException($e->getMessage()); + throw new AuthenticationException($e->getMessage(), $e->getCode()); break; default: - throw $e; + throw new ClientException($e->getMessage(), $e->getCode(), $e); break; } } + + return new YouTrackResponse($response); } /** * Create and send an GET HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function get(string $uri, array $formData = []): ResponseContract + public function get(string $uri, array $options = []): ResponseContract { - return $this->request('GET', $uri, $formData); + return $this->request('GET', $uri, $options); } /** * Create and send an POST HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function post(string $uri, array $formData = []): ResponseContract + public function post(string $uri, array $options = []): ResponseContract { - return $this->request('POST', $uri, $formData); + return $this->request('POST', $uri, $options); } /** * Create and send an PUT HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function put(string $uri, array $formData = []): ResponseContract + public function put(string $uri, array $options = []): ResponseContract { - return $this->request('PUT', $uri, $formData); + return $this->request('PUT', $uri, $options); } /** * Create and send an DELETE HTTP request. * * @param string $uri - * @param array $formData + * @param array $options * @return \Cog\YouTrack\Rest\Response\Contracts\Response + * + * @throws \Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException + * @throws \Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException + * @throws \Cog\YouTrack\Rest\Client\Exceptions\ClientException */ - public function delete(string $uri, array $formData = []): ResponseContract + public function delete(string $uri, array $options = []): ResponseContract { - return $this->request('DELETE', $uri, $formData); + return $this->request('DELETE', $uri, $options); } /** @@ -198,18 +211,22 @@ protected function buildOptions(array $formData = []): array /** * Build request headers. * - * @param array $headers + * @param array $options * @return array */ - protected function buildHeaders(array $headers = []): array + protected function buildHeaders(array $options = []): array { $this->headers = [ - 'User-Agent' => 'Cog-YouTrack-REST-PHP/' . self::CLIENT_VERSION, + 'User-Agent' => 'Cog-YouTrack-REST-PHP/' . self::VERSION, 'Accept' => 'application/json', ]; $this->authorizer->appendHeadersTo($this); - return array_merge($this->headers, $headers); + if (isset($options['headers'])) { + $this->headers = array_merge($this->headers, $options['headers']); + } + + return $this->headers; } } diff --git a/src/HttpClient/Contracts/HttpClient.php b/src/HttpClient/Contracts/HttpClient.php new file mode 100644 index 0000000..3e6ca64 --- /dev/null +++ b/src/HttpClient/Contracts/HttpClient.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\YouTrack\Rest\HttpClient\Contracts; + +use Psr\Http\Message\ResponseInterface; + +/** + * Interface HttpClient. + * + * @package Cog\YouTrack\Rest\HttpClient\Contracts + */ +interface HttpClient +{ + /** + * Send request to the server and fetch the raw response. + * + * @param string $method Request Method + * @param string $uri URI/Endpoint to send the request to + * @param array $options Additional Options + * @return \Psr\Http\Message\ResponseInterface Raw response from the server + * + * @throws \Cog\YouTrack\Rest\HttpClient\Exceptions\HttpClientException + */ + public function request(string $method, string $uri, array $options = []): ResponseInterface; +} diff --git a/src/HttpClient/Exceptions/HttpClientException.php b/src/HttpClient/Exceptions/HttpClientException.php new file mode 100644 index 0000000..341defd --- /dev/null +++ b/src/HttpClient/Exceptions/HttpClientException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\YouTrack\Rest\HttpClient\Exceptions; + +use Exception; + +/** + * Class HttpClientException. + * + * @package Cog\YouTrack\Rest\HttpClient\Exceptions + */ +class HttpClientException extends Exception +{ + // +} diff --git a/src/HttpClient/GuzzleHttpClient.php b/src/HttpClient/GuzzleHttpClient.php new file mode 100644 index 0000000..7304c0b --- /dev/null +++ b/src/HttpClient/GuzzleHttpClient.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cog\YouTrack\Rest\HttpClient; + +use Cog\YouTrack\Rest\HttpClient\Contracts\HttpClient as HttpClientContract; +use Cog\YouTrack\Rest\HttpClient\Exceptions\HttpClientException; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\BadResponseException; +use GuzzleHttp\Exception\RequestException; +use Psr\Http\Message\ResponseInterface; +use Throwable; + +/** + * Class GuzzleHttpClient. + * + * @package Cog\YouTrack\Rest\HttpClient + */ +class GuzzleHttpClient implements HttpClientContract +{ + /** + * GuzzleHttp client. + * + * @var \GuzzleHttp\Client + */ + protected $httpClient; + + /** + * Create a new GuzzleHttpClient instance. + * + * @param \GuzzleHttp\Client|null $httpClient + */ + public function __construct(Client $httpClient = null) + { + $this->httpClient = $httpClient; + } + + /** + * Send request to the server and fetch the raw response. + * + * @param string $method Request Method + * @param string $uri URI/Endpoint to send the request to + * @param array $options Additional Options + * @return \Psr\Http\Message\ResponseInterface Raw response from the server + * + * @throws \Cog\YouTrack\Rest\HttpClient\Exceptions\HttpClientException + */ + public function request(string $method, string $uri, array $options = []): ResponseInterface + { + try { + return $this->httpClient->request($method, $uri, $this->buildOptions($options)); + } catch (BadResponseException $e) { + throw new HttpClientException($e->getResponse()->getBody()->getContents(), $e->getCode(), $e); + } catch (RequestException $e) { + $rawResponse = $e->getResponse(); + if (!$rawResponse instanceof ResponseInterface) { + throw new HttpClientException($e->getMessage(), $e->getCode(), $e); + } + throw new HttpClientException($rawResponse->getBody()->getContents(), $e->getCode(), $e); + } catch (Throwable $e) { + throw new HttpClientException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Build Http Client Request options. + * + * @param array $options + * @return array + */ + private function buildOptions(array $options): array + { + return $this->appendUserAgent($options); + } + + /** + * Append User-Agent header to Request options. + * + * @param array $options + * @return array + */ + private function appendUserAgent(array $options): array + { + $defaultAgent = 'GuzzleHttp/' . Client::VERSION; + if (extension_loaded('curl') && function_exists('curl_version')) { + $defaultAgent .= ' curl/' . \curl_version()['version']; + } + $defaultAgent .= ' PHP/' . PHP_VERSION; + + if (!isset($options['headers']['User-Agent'])) { + $options['headers']['User-Agent'] = $defaultAgent; + } + + $options['headers']['User-Agent'] .= ' ' . $defaultAgent; + + return $options; + } +} diff --git a/tests/Feature/Authenticator/CookieAuthorizerTest.php b/tests/Feature/Authenticator/CookieAuthorizerTest.php index bb385a3..f8dd2d8 100644 --- a/tests/Feature/Authenticator/CookieAuthorizerTest.php +++ b/tests/Feature/Authenticator/CookieAuthorizerTest.php @@ -17,6 +17,7 @@ use Cog\YouTrack\Rest\Authenticator\Exceptions\AuthenticationException; use Cog\YouTrack\Rest\Authorizer\CookieAuthorizer; use Cog\YouTrack\Rest\Client\YouTrackClient; +use Cog\YouTrack\Rest\HttpClient\GuzzleHttpClient; use Cog\YouTrack\Rest\Tests\FeatureTestCase; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Handler\MockHandler; @@ -36,10 +37,10 @@ public function it_throws_exception_on_failed_cookie_authentication() $this->createFakeResponse(403, 'incorrect-login'), ]); $handler = HandlerStack::create($mock); - $http = new HttpClient(['handler' => $handler]); + $httpClient = new GuzzleHttpClient(new HttpClient(['handler' => $handler])); $authenticator = new CookieAuthenticator('invalid-user', 'invalid-pass'); $authorizer = new CookieAuthorizer($authenticator); - $client = new YouTrackClient($http, $authorizer); + $client = new YouTrackClient($httpClient, $authorizer); $this->expectException(AuthenticationException::class); @@ -49,9 +50,9 @@ public function it_throws_exception_on_failed_cookie_authentication() /** @todo test */ public function it_can_successfully_authenticate() { - $http = new HttpClient([ + $http = new GuzzleHttpClient(new HttpClient([ 'base_uri' => 'http://localhost', - ]); + ])); $authenticator = new CookieAuthenticator('valid-user', 'valid-pass'); $authorizer = new CookieAuthorizer($authenticator); diff --git a/tests/Feature/Authenticator/TokenAuthorizerTest.php b/tests/Feature/Authenticator/TokenAuthorizerTest.php index 8af46e5..5269f35 100644 --- a/tests/Feature/Authenticator/TokenAuthorizerTest.php +++ b/tests/Feature/Authenticator/TokenAuthorizerTest.php @@ -16,6 +16,7 @@ use Cog\YouTrack\Rest\Authorizer\Exceptions\InvalidTokenException; use Cog\YouTrack\Rest\Authorizer\TokenAuthorizer; use Cog\YouTrack\Rest\Client\YouTrackClient; +use Cog\YouTrack\Rest\HttpClient\GuzzleHttpClient; use Cog\YouTrack\Rest\Tests\FeatureTestCase; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Handler\MockHandler; @@ -35,9 +36,9 @@ public function it_throws_exception_on_failed_token_authorization() $this->createFakeResponse(401, 'unauthorized'), ]); $handler = HandlerStack::create($mock); - $http = new HttpClient(['handler' => $handler]); + $httpClient = new GuzzleHttpClient(new HttpClient(['handler' => $handler])); $authorizer = new TokenAuthorizer('invalid-token'); - $client = new YouTrackClient($http, $authorizer); + $client = new YouTrackClient($httpClient, $authorizer); $this->expectException(InvalidTokenException::class);