diff --git a/lib/Github/Api/AbstractApi.php b/lib/Github/Api/AbstractApi.php index be6063d3cfb..ecf74d5cd88 100644 --- a/lib/Github/Api/AbstractApi.php +++ b/lib/Github/Api/AbstractApi.php @@ -35,7 +35,7 @@ public function configure() */ protected function get($path, array $parameters = array(), $requestHeaders = array()) { - $response = $this->client->getHttpClient()->get($path, $parameters, $requestHeaders); + $response = $this->client->executeRequest('GET', $path, $parameters, $requestHeaders); return $response->getContent(); } @@ -45,7 +45,7 @@ protected function get($path, array $parameters = array(), $requestHeaders = arr */ protected function post($path, array $parameters = array(), $requestHeaders = array()) { - $response = $this->client->getHttpClient()->post($path, $parameters, $requestHeaders); + $response = $this->client->executeRequest('POST', $path, $parameters, $requestHeaders); return $response->getContent(); } @@ -55,7 +55,7 @@ protected function post($path, array $parameters = array(), $requestHeaders = ar */ protected function patch($path, array $parameters = array(), $requestHeaders = array()) { - $response = $this->client->getHttpClient()->patch($path, $parameters, $requestHeaders); + $response = $this->client->executeRequest('PATCH', $path, $parameters, $requestHeaders); return $response->getContent(); } @@ -65,7 +65,7 @@ protected function patch($path, array $parameters = array(), $requestHeaders = a */ protected function put($path, array $parameters = array(), $requestHeaders = array()) { - $response = $this->client->getHttpClient()->put($path, $parameters, $requestHeaders); + $response = $this->client->executeRequest('PUT', $path, $parameters, $requestHeaders); return $response->getContent(); } @@ -75,7 +75,7 @@ protected function put($path, array $parameters = array(), $requestHeaders = arr */ protected function delete($path, array $parameters = array(), $requestHeaders = array()) { - $response = $this->client->getHttpClient()->delete($path, $parameters, $requestHeaders); + $response = $this->client->executeRequest('DELETE', $path, $parameters, $requestHeaders); return $response->getContent(); } diff --git a/lib/Github/Client.php b/lib/Github/Client.php index 3338a1b3b7c..34b62dc1194 100644 --- a/lib/Github/Client.php +++ b/lib/Github/Client.php @@ -2,14 +2,10 @@ namespace Github; -use Buzz\Client\Curl; -use Buzz\Client\ClientInterface; - use Github\Api\ApiInterface; use Github\Exception\InvalidArgumentException; -use Github\HttpClient\HttpClient; +use Github\HttpClient\Adapter\Buzz\HttpClient; use Github\HttpClient\HttpClientInterface; -use Github\HttpClient\Listener\AuthListener; /** * Simple yet very cool PHP GitHub client @@ -53,7 +49,6 @@ class Client 'user_agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', 'timeout' => 10, - 'api_limit' => 5000, 'api_version' => 'beta', 'cache_dir' => null @@ -160,15 +155,35 @@ public function authenticate($tokenOrLogin, $password = null, $authMethod = null $password = null; } - $this->httpClient->addListener( - new AuthListener( - $authMethod, - array( - 'tokenOrLogin' => $tokenOrLogin, - 'password' => $password - ) - ) - ); + switch ($authMethod) { + case Client::AUTH_HTTP_PASSWORD: + if (!$tokenOrLogin || !$password) { + throw new InvalidArgumentException('You need to set username with password!'); + } + break; + case Client::AUTH_HTTP_TOKEN: + if (!$tokenOrLogin) { + throw new InvalidArgumentException('You need to set OAuth token!'); + } + break; + case Client::AUTH_URL_CLIENT_ID: + if (!$tokenOrLogin || !$password) { + throw new InvalidArgumentException('You need to set client_id and client_secret!'); + } + break; + case Client::AUTH_URL_TOKEN: + if (!$tokenOrLogin) { + throw new InvalidArgumentException('You need to set OAuth token!'); + } + break; + } + + $this->httpClient->authenticate($authMethod, $tokenOrLogin, $password); + } + + public function executeRequest($method, $path, $parameters, $headers) + { + return $this->httpClient->request($path, $parameters, $method, $headers)->getContent(); } /** diff --git a/lib/Github/Exception/InvalidJsonResponse.php b/lib/Github/Exception/InvalidJsonResponse.php new file mode 100644 index 00000000000..b0344086893 --- /dev/null +++ b/lib/Github/Exception/InvalidJsonResponse.php @@ -0,0 +1,19 @@ +body = $body; + parent::__construct('Invalid Json Response', $code, $previous); + } + + public function getBody() + { + return $this->body; + } +} diff --git a/lib/Github/HttpClient/AbstractAdapter.php b/lib/Github/HttpClient/AbstractAdapter.php new file mode 100644 index 00000000000..392aeda0d2f --- /dev/null +++ b/lib/Github/HttpClient/AbstractAdapter.php @@ -0,0 +1,100 @@ + 'https://api.github.com/', + 'user_agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', + 'timeout' => 10, + 'api_version' => 'beta', + 'cache_dir' => null + ); + /** + * @var array + */ + protected $headers; + + /** + * {@inheritDoc} + */ + public function setOption($name, $value) + { + $this->options[$name] = $value; + } + + /** + * {@inheritDoc} + */ + public function setHeaders(array $headers) + { + $this->headers = array_merge($this->headers, $headers); + } + + /** + * {@inheritDoc} + */ + public function clearHeaders() + { + $this->headers = array( + sprintf('Accept: application/vnd.github.%s+json', $this->options['api_version']) + ); + } + + /** + * {@inheritDoc} + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + /** + * {@inheritDoc} + */ + public function getLastResponse() + { + return $this->lastResponse; + } + + /** + * {@inheritDoc} + */ + public function getAPILimit() + { + if (!$this->getLastRequest()) { + $this->get('/rate_limit'); + } + + return (int) $this->getLastRequest()->getHeaderAsString('X-RateLimit-Limit'); + } + + /** + * {@inheritDoc} + */ + public function getAPIRemaining() + { + if (!$this->getLastRequest()) { + $this->get('/rate_limit'); + } + + return (int) $this->getLastRequest()->getHeaderAsString('X-RateLimit-Remaining'); + } +} diff --git a/lib/Github/HttpClient/CachedHttpClient.php b/lib/Github/HttpClient/Adapter/Buzz/CachedHttpClient.php similarity index 97% rename from lib/Github/HttpClient/CachedHttpClient.php rename to lib/Github/HttpClient/Adapter/Buzz/CachedHttpClient.php index 5cb2c826dfc..c698ed782cc 100644 --- a/lib/Github/HttpClient/CachedHttpClient.php +++ b/lib/Github/HttpClient/Adapter/Buzz/CachedHttpClient.php @@ -1,6 +1,6 @@ */ -class HttpClient implements HttpClientInterface +class HttpClient extends AbstractAdapter { /** * @var array @@ -29,8 +30,6 @@ class HttpClient implements HttpClientInterface 'user_agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', 'timeout' => 10, - - 'api_limit' => 5000, 'api_version' => 'beta', 'cache_dir' => null @@ -39,13 +38,6 @@ class HttpClient implements HttpClientInterface * @var array */ protected $listeners = array(); - /** - * @var array - */ - protected $headers = array(); - - private $lastResponse; - private $lastRequest; /** * @param array $options @@ -60,43 +52,27 @@ public function __construct(array $options = array(), ClientInterface $client = $this->options = array_merge($this->options, $options); $this->client = $client; - $this->addListener(new ErrorListener($this->options)); + $this->addListener(new ErrorListener()); $this->clearHeaders(); } /** - * {@inheritDoc} - */ - public function setOption($name, $value) - { - $this->options[$name] = $value; - } - - /** - * {@inheritDoc} - */ - public function setHeaders(array $headers) - { - $this->headers = array_merge($this->headers, $headers); - } - - /** - * Clears used headers + * @param ListenerInterface $listener */ - public function clearHeaders() + public function addListener(ListenerInterface $listener) { - $this->headers = array( - sprintf('Accept: application/vnd.github.%s+json', $this->options['api_version']) - ); + $this->listeners[get_class($listener)] = $listener; } /** - * @param ListenerInterface $listener + * Returns listeners + * + * @return array */ - public function addListener(ListenerInterface $listener) + public function getListeners() { - $this->listeners[get_class($listener)] = $listener; + return $this->listeners; } /** @@ -171,32 +147,32 @@ public function request($path, array $parameters = array(), $httpMethod = 'GET', throw new RuntimeException($e->getMessage()); } - $this->lastRequest = $request; - $this->lastResponse = $response; - if ($hasListeners) { foreach ($this->listeners as $listener) { $listener->postSend($request, $response); } } - return $response; - } + $this->lastRequest = new Request($request); + $this->lastResponse = new Response($response); - /** - * @return Request - */ - public function getLastRequest() - { - return $this->lastRequest; + return $response; } /** - * @return Response + * {@inheritdoc} */ - public function getLastResponse() + public function authenticate($method, $tokenOrLogin, $password = null) { - return $this->lastResponse; + $this->addListener( + new AuthListener( + $method, + array( + 'tokenOrLogin' => $tokenOrLogin, + 'password' => $password + ) + ) + );; } /** @@ -205,9 +181,9 @@ public function getLastResponse() * * @return Request */ - protected function createRequest($httpMethod, $url) + private function createRequest($httpMethod, $url) { - $request = new Request($httpMethod); + $request = new BuzzRequest($httpMethod); $request->setHeaders($this->headers); $request->fromUrl($url); @@ -217,8 +193,8 @@ protected function createRequest($httpMethod, $url) /** * @return Response */ - protected function createResponse() + private function createResponse() { - return new Response(); + return new BuzzResponse(); } } diff --git a/lib/Github/HttpClient/Listener/AuthListener.php b/lib/Github/HttpClient/Adapter/Buzz/Listener/AuthListener.php similarity index 89% rename from lib/Github/HttpClient/Listener/AuthListener.php rename to lib/Github/HttpClient/Adapter/Buzz/Listener/AuthListener.php index eba95669ad2..46746be47dd 100644 --- a/lib/Github/HttpClient/Listener/AuthListener.php +++ b/lib/Github/HttpClient/Adapter/Buzz/Listener/AuthListener.php @@ -1,6 +1,6 @@ options = $options; } + /** + * Returns authentication method + * + * @return string + */ + public function getMethod() + { + return $this->method; + } + + /** + * Returns Options + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + /** * {@inheritDoc} * diff --git a/lib/Github/HttpClient/Listener/ErrorListener.php b/lib/Github/HttpClient/Adapter/Buzz/Listener/ErrorListener.php similarity index 83% rename from lib/Github/HttpClient/Listener/ErrorListener.php rename to lib/Github/HttpClient/Adapter/Buzz/Listener/ErrorListener.php index 1d537240900..cb031e90801 100644 --- a/lib/Github/HttpClient/Listener/ErrorListener.php +++ b/lib/Github/HttpClient/Adapter/Buzz/Listener/ErrorListener.php @@ -1,6 +1,6 @@ options = $options; - } - /** * {@inheritDoc} */ @@ -40,11 +27,10 @@ public function preSend(RequestInterface $request) */ public function postSend(RequestInterface $request, MessageInterface $response) { - /** @var $response \Github\HttpClient\Message\Response */ + /** @var $response \Github\HttpClient\ResponseInterface */ if ($response->isClientError() || $response->isServerError()) { - $remaining = $response->getHeader('X-RateLimit-Remaining'); - if (null !== $remaining && 1 > $remaining) { - throw new ApiLimitExceedException($this->options['api_limit']); + if (0 === (int) $response->getHeader('X-RateLimit-Remaining')) { + throw new ApiLimitExceedException($response->getHeader('X-RateLimit-Limit')); } $content = $response->getContent(); diff --git a/lib/Github/HttpClient/Adapter/Buzz/Message/Request.php b/lib/Github/HttpClient/Adapter/Buzz/Message/Request.php new file mode 100644 index 00000000000..60809beec70 --- /dev/null +++ b/lib/Github/HttpClient/Adapter/Buzz/Message/Request.php @@ -0,0 +1,21 @@ +request = $request; + } + + public function getAdapterRequest() + { + return $this->request; + } +} diff --git a/lib/Github/HttpClient/Adapter/Buzz/Message/Response.php b/lib/Github/HttpClient/Adapter/Buzz/Message/Response.php new file mode 100644 index 00000000000..7d10b004427 --- /dev/null +++ b/lib/Github/HttpClient/Adapter/Buzz/Message/Response.php @@ -0,0 +1,59 @@ +response = $response; + } + + /** + * {@inheritdoc} + */ + public function getStatusCode() + { + return $this->response->getStatusCode(); + } + + /** + * {@inheritdoc} + */ + public function getHeaderAsString($name) + { + return $this->response->getHeader($name); + } + + /** + * {@inheritdoc} + */ + public function isNotModified() + { + return 304 === $this->getStatusCode(); + } + + /** + * {@inheritdoc} + */ + public function getAdapterResponse() + { + return $this->response; + } + + /** + * {@inheritdoc} + * + * @return BuzzResponse + */ + public function getRawBody() + { + return $this->response->getContent(); + } +} diff --git a/lib/Github/HttpClient/Adapter/Guzzle/HttpClient.php b/lib/Github/HttpClient/Adapter/Guzzle/HttpClient.php new file mode 100644 index 00000000000..0b92e664048 --- /dev/null +++ b/lib/Github/HttpClient/Adapter/Guzzle/HttpClient.php @@ -0,0 +1,152 @@ +setBaseUrl($this->options['base_url']); + $client->setSslVerification(false); + + $opts = $client->getConfig(Client::CURL_OPTIONS); + $opts[CURLOPT_TIMEOUT] = $this->options['timeout']; + + $client->getConfig()->set(Client::CURL_OPTIONS, $opts); + + $this->options = array_merge($this->options, $options); + $this->client = $client; + +// $this->addListener(new ErrorListener($this->options)); + + $this->clearHeaders(); + } + + /** + * {@inheritDoc} + */ + public function get($path, array $parameters = array(), array $headers = array()) + { + if (0 < count($parameters)) { + $path .= (false === strpos($path, '?') ? '?' : '&') . http_build_query($parameters, '', '&'); + } + + return $this->request($path, array(), 'GET', $headers); + } + + /** + * {@inheritDoc} + */ + public function post($path, array $parameters = array(), array $headers = array()) + { + return $this->request($path, $parameters, 'POST', $headers); + } + + /** + * {@inheritDoc} + */ + public function patch($path, array $parameters = array(), array $headers = array()) + { + return $this->request($path, $parameters, 'PATCH', $headers); + } + + /** + * {@inheritDoc} + */ + public function delete($path, array $parameters = array(), array $headers = array()) + { + return $this->request($path, $parameters, 'DELETE', $headers); + } + + /** + * {@inheritDoc} + */ + public function put($path, array $parameters = array(), array $headers = array()) + { + return $this->request($path, $parameters, 'PUT', $headers); + } + + /** + * {@inheritDoc} + */ + public function request($path, array $parameters = array(), $httpMethod = 'GET', array $headers = array()) + { + $path = trim($path, '/'); + + $request = $this->client->createRequest($httpMethod, $path, $headers, json_encode($parameters)); + + try { + $response = new Response($request->send()); + } catch (\Guzzle\Common\Exception\GuzzleException $e) { + throw new RuntimeException($e->getMessage()); + } + + $this->lastRequest = $request; + $this->lastResponse = $response; + + return $response; + } + + /** + * {@inheritdoc} + */ + public function authenticate($method, $tokenOrLogin, $password = null) + { + switch ($method) { + case GithubClient::AUTH_HTTP_PASSWORD: + $this->client->getEventDispatcher()->addListener('request.create', function (Event $event) { + $event['request']->setHeader('Authorization', sprintf('Basic ', base64_encode($tokenOrLogin . ':' . $password))); + }); + break; + case GithubClient::AUTH_HTTP_TOKEN: + $this->client->getEventDispatcher()->addListener('request.create', function (Event $event) { + $event['request']->setHeader('Authorization', sprintf('token ', $tokenOrLogin)); + }); + break; + case GithubClient::AUTH_URL_CLIENT_ID: + $this->client->getEventDispatcher()->addListener('request.create', function (Event $event) { + $url = $event['request']->getUrl(); + + $parameters = array( + 'client_id' => $tokenOrLogin, + 'client_secret' => $password, + ); + + $url .= (false === strpos($url, '?') ? '?' : '&') . utf8_encode(http_build_query($parameters, '', '&')); + + $event['request']->setUrl($url); + }); + break; + case GithubClient::AUTH_URL_TOKEN: + $this->client->getEventDispatcher()->addListener('request.create', function (Event $event) { + $url = $event['request']->getUrl(); + $url .= (false === strpos($url, '?') ? '?' : '&') . utf8_encode(http_build_query(array('access_token' => $tokenOrLogin), '', '&')); + + $event['request']->setUrl($url); + }); + break; + default: + throw new RuntimeException(sprintf('%s not yet implemented', $method)); + break; + } + } +} diff --git a/lib/Github/HttpClient/Adapter/Guzzle/Message/Response.php b/lib/Github/HttpClient/Adapter/Guzzle/Message/Response.php new file mode 100644 index 00000000000..6f300baac84 --- /dev/null +++ b/lib/Github/HttpClient/Adapter/Guzzle/Message/Response.php @@ -0,0 +1,51 @@ +response = $response; + } + + /** + * {@inheritdoc} + */ + public function getRawBody() + { + return $this->response->getBody(true); + } + + /** + * {@inheritdoc} + */ + public function getStatusCode() + { + return $this->response->getStatusCode(); + } + + /** + * {@inheritdoc} + */ + public function getHeaderAsString($name) + { + return $this->response->getHeader($name, true); + } + + /** + * {@inheritdoc} + * + * @return GuzzleResponse + */ + public function getAdapterResponse() + { + return $this->response; + } +} diff --git a/lib/Github/HttpClient/Cache/CacheInterface.php b/lib/Github/HttpClient/Cache/CacheInterface.php index b2889d1e4db..bc4aa00da21 100644 --- a/lib/Github/HttpClient/Cache/CacheInterface.php +++ b/lib/Github/HttpClient/Cache/CacheInterface.php @@ -2,7 +2,7 @@ namespace Github\HttpClient\Cache; -use Github\HttpClient\Message\Response; +use Github\HttpClient\ResponseInterface; /** * Caches github api responses @@ -21,18 +21,18 @@ public function getModifiedSince($id); /** * @param string $id The id of the cached resource * - * @return Response The cached response object + * @return ResponseInterface The cached response object * * @throws \InvalidArgumentException If cache data don't exists */ public function get($id); /** - * @param string $id The id of the cached resource - * @param Response $response The response to cache + * @param string $id The id of the cached resource + * @param ResponseInterface $response The response to cache * * @throws \InvalidArgumentException If cache data cannot be saved */ - public function set($id, Response $response); + public function set($id, ResponseInterface $response); } diff --git a/lib/Github/HttpClient/Cache/FilesystemCache.php b/lib/Github/HttpClient/Cache/FilesystemCache.php index c700d31cb2e..1d81baad7bc 100644 --- a/lib/Github/HttpClient/Cache/FilesystemCache.php +++ b/lib/Github/HttpClient/Cache/FilesystemCache.php @@ -2,7 +2,7 @@ namespace Github\HttpClient\Cache; -use Github\HttpClient\Message\Response; +use Github\HttpClient\ResponseInterface; class FilesystemCache implements CacheInterface { @@ -34,7 +34,7 @@ public function get($id) /** * {@inheritdoc} */ - public function set($id, Response $response) + public function set($id, ResponseInterface $response) { if (!is_dir($this->path)) { @mkdir($this->path, 0777, true); diff --git a/lib/Github/HttpClient/HttpClientInterface.php b/lib/Github/HttpClient/HttpClientInterface.php index 7c327d625e3..830e1de2776 100644 --- a/lib/Github/HttpClient/HttpClientInterface.php +++ b/lib/Github/HttpClient/HttpClientInterface.php @@ -95,4 +95,46 @@ public function setOption($name, $value); * @param array $headers */ public function setHeaders(array $headers); + + /** + * Removes all headers previously set + */ + public function clearHeaders(); + + /** + * Authenticate HttpClient requests with parameters + * + * @param string $method + * @param string $tokenOrLogin + * @param string|null $password + */ + public function authenticate($method, $tokenOrLogin, $password = null); + + /** + * Return the last request that has been executed + * + * @return RequestInterface + */ + public function getLastRequest(); + + /** + * Return the last response that has been received + * + * @return ResponseInterface + */ + public function getLastResponse(); + + /** + * Return the API Limit with the current authentication state + * + * @return Integer + */ + public function getAPILimit(); + + /** + * Return the API remaining request quantity with the current authentication state + * + * @return Integer + */ + public function getAPIRemaining(); } diff --git a/lib/Github/HttpClient/Message/AbstractResponse.php b/lib/Github/HttpClient/Message/AbstractResponse.php new file mode 100644 index 00000000000..64d6f4ce2a6 --- /dev/null +++ b/lib/Github/HttpClient/Message/AbstractResponse.php @@ -0,0 +1,53 @@ +getRawBody(); + $content = json_decode($rawBody, true); + + if (JSON_ERROR_NONE !== json_last_error()) { + throw new InvalidJsonResponse($rawBody); + } + + return $content; + } + + /** + * {@inheritdoc} + */ + public function getPagination() + { + $header = $this->getHeaderAsString('Link'); + if (empty($header)) { + return null; + } + + $pagination = array(); + foreach (explode(',', $header) as $link) { + preg_match('/<(.*)>; rel="(.*)"/i', trim($link, ','), $match); + + if (3 === count($match)) { + $pagination[$match[2]] = $match[1]; + } + } + + return $pagination; + } + + /** + * {@inheritdoc} + */ + public function isNotModified() + { + return 304 === $this->getStatusCode(); + } +} diff --git a/lib/Github/HttpClient/Message/Request.php b/lib/Github/HttpClient/Message/Request.php deleted file mode 100644 index cbc206809de..00000000000 --- a/lib/Github/HttpClient/Message/Request.php +++ /dev/null @@ -1,10 +0,0 @@ -getHeader('Link'); - if (empty($header)) { - return null; - } - - $pagination = array(); - foreach (explode(',', $header) as $link) { - preg_match('/<(.*)>; rel="(.*)"/i', trim($link, ','), $match); - - if (3 === count($match)) { - $pagination[$match[2]] = $match[1]; - } - } - - return $pagination; - } - - /** - * {@inheritDoc} - */ - public function getApiLimit() - { - $header = $this->getHeaderAttributes('X-RateLimit-Remaining'); - if (!empty($header)) { - $this->remainingCalls = $header; - } - - if (null !== $this->remainingCalls && 1 > $this->remainingCalls) { - throw new ApiLimitExceedException($this->options['api_limit']); - } - } - - /** - * Is not modified - * - * @return Boolean - */ - public function isNotModified() - { - return 304 === $this->getStatusCode(); - } -} diff --git a/lib/Github/HttpClient/RequestInterface.php b/lib/Github/HttpClient/RequestInterface.php new file mode 100644 index 00000000000..5a2131af0f8 --- /dev/null +++ b/lib/Github/HttpClient/RequestInterface.php @@ -0,0 +1,11 @@ +getMock('Github\HttpClient\HttpClient', array(), array(array(), $this->getHttpClientMock())); + return $this->getMock('Github\HttpClient\HttpClientInterface', array(), array(array(), $this->getHttpClientMock())); } protected function getHttpClientMock() @@ -158,7 +158,7 @@ class AbstractApiTestInstance extends AbstractApi */ public function get($path, array $parameters = array(), $requestHeaders = array()) { - return $this->client->getHttpClient()->get($path, $parameters, $requestHeaders); + return $this->client->executeRequest('GET', $path, $parameters, $requestHeaders); } /** @@ -166,7 +166,7 @@ public function get($path, array $parameters = array(), $requestHeaders = array( */ public function post($path, array $parameters = array(), $requestHeaders = array()) { - return $this->client->getHttpClient()->post($path, $parameters, $requestHeaders); + return $this->client->executeRequest('POST', $path, $parameters, $requestHeaders); } /** @@ -174,7 +174,7 @@ public function post($path, array $parameters = array(), $requestHeaders = array */ public function patch($path, array $parameters = array(), $requestHeaders = array()) { - return $this->client->getHttpClient()->patch($path, $parameters, $requestHeaders); + return $this->client->executeRequest('PATCH', $path, $parameters, $requestHeaders); } /** @@ -182,7 +182,7 @@ public function patch($path, array $parameters = array(), $requestHeaders = arra */ public function put($path, array $parameters = array(), $requestHeaders = array()) { - return $this->client->getHttpClient()->put($path, $parameters, $requestHeaders); + return $this->client->executeRequest('PUT', $path, $parameters, $requestHeaders); } /** @@ -190,6 +190,6 @@ public function put($path, array $parameters = array(), $requestHeaders = array( */ public function delete($path, array $parameters = array(), $requestHeaders = array()) { - return $this->client->getHttpClient()->delete($path, $parameters, $requestHeaders); + return $this->client->executeRequest('DELETE', $path, $parameters, $requestHeaders); } } diff --git a/test/Github/Tests/Api/TestCase.php b/test/Github/Tests/Api/TestCase.php index 5bae9b02972..cd59a88aecb 100644 --- a/test/Github/Tests/Api/TestCase.php +++ b/test/Github/Tests/Api/TestCase.php @@ -21,7 +21,7 @@ protected function getApiMock() ->expects($this->any()) ->method('send'); - $mock = $this->getMock('Github\HttpClient\HttpClient', array(), array(array(), $httpClient)); + $mock = $this->getMock('Github\HttpClient\HttpClientInterface', array(), array(array(), $httpClient)); $client = new \Github\Client($mock); $client->setHttpClient($mock); diff --git a/test/Github/Tests/ClientTest.php b/test/Github/Tests/ClientTest.php index 4e96dfcccbb..f41f1c42432 100644 --- a/test/Github/Tests/ClientTest.php +++ b/test/Github/Tests/ClientTest.php @@ -3,8 +3,7 @@ namespace Github\Tests; use Github\Client; -use Github\HttpClient\Listener\AuthListener; -use Github\Exception\InvalidArgumentException; +use Github\HttpClient\Adapter\Buzz\Listener\AuthListener; class ClientTest extends \PHPUnit_Framework_TestCase { @@ -15,65 +14,18 @@ public function shouldNotHaveToPassHttpClientToConstructor() { $client = new Client(); - $this->assertInstanceOf('Github\HttpClient\HttpClient', $client->getHttpClient()); - } - - /** - * @test - */ - public function shouldPassHttpClientInterfaceToConstructor() - { - $client = new Client($this->getHttpClientMock()); - $this->assertInstanceOf('Github\HttpClient\HttpClientInterface', $client->getHttpClient()); } /** * @test - * @dataProvider getAuthenticationFullData */ - public function shouldAuthenticateUsingAllGivenParameters($login, $password, $method) - { - $httpClient = $this->getHttpClientMock(array('addListener')); - $httpClient->expects($this->once()) - ->method('addListener') - ->with(new AuthListener($method, array('tokenOrLogin' => $login, 'password' => $password))); - - $client = new Client($httpClient); - $client->authenticate($login, $password, $method); - } - - public function getAuthenticationFullData() - { - return array( - array('login', 'password', Client::AUTH_HTTP_PASSWORD), - array('token', null, Client::AUTH_HTTP_TOKEN), - array('token', null, Client::AUTH_URL_TOKEN), - array('client_id', 'client_secret', Client::AUTH_URL_CLIENT_ID), - ); - } - - /** - * @test - * @dataProvider getAuthenticationPartialData - */ - public function shouldAuthenticateUsingGivenParameters($token, $method) + public function shouldPassHttpClientInterfaceToConstructor() { - $httpClient = $this->getHttpClientMock(array('addListener')); - $httpClient->expects($this->once()) - ->method('addListener') - ->with(new AuthListener($method, array('tokenOrLogin' => $token, 'password' => null))); - + $httpClient = $this->getHttpClientMock(); $client = new Client($httpClient); - $client->authenticate($token, $method); - } - public function getAuthenticationPartialData() - { - return array( - array('token', Client::AUTH_HTTP_TOKEN), - array('token', Client::AUTH_URL_TOKEN), - ); + $this->assertEquals($httpClient, $client->getHttpClient()); } /** @@ -93,7 +45,7 @@ public function shouldThrowExceptionWhenAuthenticatingWithoutMethodSet() */ public function shouldClearHeadersLazy() { - $httpClient = $this->getHttpClientMock(array('clearHeaders')); + $httpClient = $this->getHttpClientMock(); $httpClient->expects($this->once())->method('clearHeaders'); $client = new Client($httpClient); @@ -172,7 +124,11 @@ public function getApiClassesProvider() public function getHttpClientMock(array $methods = array()) { $methods = array_merge( - array('get', 'post', 'patch', 'put', 'delete', 'request', 'setOption', 'setHeaders'), + array( + 'get', 'post', 'patch', 'put', 'delete', 'request', + 'setOption', 'setHeaders', 'clearHeaders', 'authenticate', + 'getLastRequest', 'getLastResponse', 'getAPILimit', 'getAPIRemaining' + ), $methods ); diff --git a/test/Github/Tests/HttpClient/CachedHttpClientTest.php b/test/Github/Tests/HttpClient/Adapter/Buzz/CachedHttpClientTest.php similarity index 93% rename from test/Github/Tests/HttpClient/CachedHttpClientTest.php rename to test/Github/Tests/HttpClient/Adapter/Buzz/CachedHttpClientTest.php index 3ab2f0b303e..a63bcdc7d88 100644 --- a/test/Github/Tests/HttpClient/CachedHttpClientTest.php +++ b/test/Github/Tests/HttpClient/Adapter/Buzz/CachedHttpClientTest.php @@ -1,9 +1,9 @@ 'b'); $headers = array('c' => 'd'); - $message = $this->getMock('Github\HttpClient\Message\Response'); + $message = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $message->expects($this->once()) ->method('getContent') ->will($this->returnValue('Just raw context')); @@ -186,6 +188,64 @@ public function shouldThrowExceptionWhenApiIsExceeded() $httpClient->get($path, $parameters, $headers); } + /** + * @test + * @dataProvider getAuthenticationFullData + */ + public function shouldAuthenticateUsingAllGivenParameters($login, $password, $method) + { + $httpClient = new HttpClient(); + + $n = count($httpClient->getListeners()); + + $httpClient->authenticate($method, $login, $password); + + $listeners = $httpClient->getListeners(); + $this->assertCount($n + 1, $listeners); + + $listener = array_pop($listeners); + $this->assertEquals($method, $listener->getMethod()); + $this->assertEquals(array('tokenOrLogin' => $login, 'password' => $password), $listener->getOptions()); + } + + public function getAuthenticationFullData() + { + return array( + array('login', 'password', Client::AUTH_HTTP_PASSWORD), + array('token', null, Client::AUTH_HTTP_TOKEN), + array('token', null, Client::AUTH_URL_TOKEN), + array('client_id', 'client_secret', Client::AUTH_URL_CLIENT_ID), + ); + } + + /** + * @test + * @dataProvider getAuthenticationPartialData + */ + public function shouldAuthenticateUsingGivenParameters($token, $method) + { + $httpClient = new HttpClient(); + + $n = count($httpClient->getListeners()); + + $httpClient->authenticate($method, $token); + + $listeners = $httpClient->getListeners(); + $this->assertCount($n + 1, $listeners); + + $listener = array_pop($listeners); + $this->assertEquals($method, $listener->getMethod()); + $this->assertEquals(array('tokenOrLogin' => $token, 'password' => null), $listener->getOptions()); + } + + public function getAuthenticationPartialData() + { + return array( + array('token', Client::AUTH_HTTP_TOKEN), + array('token', Client::AUTH_URL_TOKEN), + ); + } + protected function getBrowserMock() { return $this->getMock('Buzz\Client\ClientInterface', array('setTimeout', 'setVerifyPeer', 'send')); diff --git a/test/Github/Tests/HttpClient/Listener/AuthListenerTest.php b/test/Github/Tests/HttpClient/Adapter/Buzz/Listener/AuthListenerTest.php similarity index 94% rename from test/Github/Tests/HttpClient/Listener/AuthListenerTest.php rename to test/Github/Tests/HttpClient/Adapter/Buzz/Listener/AuthListenerTest.php index cfd741c7a0c..b8bb006b385 100644 --- a/test/Github/Tests/HttpClient/Listener/AuthListenerTest.php +++ b/test/Github/Tests/HttpClient/Adapter/Buzz/Listener/AuthListenerTest.php @@ -1,11 +1,11 @@ 'test')); $listener->preSend($request); @@ -169,7 +169,7 @@ public function shouldSetTokenInUrlForAuthUrlMethod() */ public function shouldSetClientDetailsInUrlForAuthUrlMethod() { - $request = new Request(Request::METHOD_GET, '/res'); + $request = new BuzzRequest(BuzzRequest::METHOD_GET, '/res'); $listener = new AuthListener(Client::AUTH_URL_CLIENT_ID, array('tokenOrLogin' => 'clientId', 'password' => 'clientSsecret')); $listener->preSend($request); diff --git a/test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php b/test/Github/Tests/HttpClient/Adapter/Buzz/Listener/ErrorListenerTest.php similarity index 84% rename from test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php rename to test/Github/Tests/HttpClient/Adapter/Buzz/Listener/ErrorListenerTest.php index fb05761e891..e3f11dee106 100644 --- a/test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php +++ b/test/Github/Tests/HttpClient/Adapter/Buzz/Listener/ErrorListenerTest.php @@ -1,8 +1,8 @@ getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(false)); - $listener = new ErrorListener(array('api_limit' => 5000)); + $listener = new ErrorListener(); $listener->postSend($this->getMock('Buzz\Message\RequestInterface'), $response); } @@ -26,7 +26,7 @@ public function shouldPassIfResponseNotHaveErrorStatus() */ public function shouldFailWhenApiLimitWasExceed() { - $response = $this->getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(true)); @@ -35,7 +35,7 @@ public function shouldFailWhenApiLimitWasExceed() ->with('X-RateLimit-Remaining') ->will($this->returnValue(0)); - $listener = new ErrorListener(array('api_limit' => 5000)); + $listener = new ErrorListener(); $listener->postSend($this->getMock('Buzz\Message\RequestInterface'), $response); } @@ -45,7 +45,7 @@ public function shouldFailWhenApiLimitWasExceed() */ public function shouldNotPassWhenContentWasNotValidJson() { - $response = $this->getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(true)); @@ -57,7 +57,7 @@ public function shouldNotPassWhenContentWasNotValidJson() ->method('getContent') ->will($this->returnValue('fail')); - $listener = new ErrorListener(array('api_limit' => 5000)); + $listener = new ErrorListener(); $listener->postSend($this->getMock('Buzz\Message\RequestInterface'), $response); } @@ -67,7 +67,7 @@ public function shouldNotPassWhenContentWasNotValidJson() */ public function shouldNotPassWhenContentWasValidJsonButStatusIsNotCovered() { - $response = $this->getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(true)); @@ -82,7 +82,7 @@ public function shouldNotPassWhenContentWasValidJsonButStatusIsNotCovered() ->method('getStatusCode') ->will($this->returnValue(404)); - $listener = new ErrorListener(array('api_limit' => 5000)); + $listener = new ErrorListener(); $listener->postSend($this->getMock('Buzz\Message\RequestInterface'), $response); } @@ -92,7 +92,7 @@ public function shouldNotPassWhenContentWasValidJsonButStatusIsNotCovered() */ public function shouldNotPassWhen400IsSent() { - $response = $this->getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(true)); @@ -107,7 +107,7 @@ public function shouldNotPassWhen400IsSent() ->method('getStatusCode') ->will($this->returnValue(400)); - $listener = new ErrorListener(array('api_limit' => 5000)); + $listener = new ErrorListener(); $listener->postSend($this->getMock('Buzz\Message\RequestInterface'), $response); } @@ -129,7 +129,7 @@ public function shouldNotPassWhen422IsSentWithErrorCode($errorCode) ) ); - $response = $this->getMock('Github\HttpClient\Message\Response'); + $response = $this->getMock('Github\HttpClient\Adapter\Buzz\Message\Response'); $response->expects($this->once()) ->method('isClientError') ->will($this->returnValue(true)); diff --git a/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php b/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php index f3655705d15..f11e9592fe0 100644 --- a/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php +++ b/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php @@ -2,7 +2,6 @@ namespace Github\Tests\HttpClient\Cache; -use Github\HttpClient\Message\Response; use Github\HttpClient\Cache\FilesystemCache; class FilesystemCacheTest extends \PHPUnit_Framework_TestCase @@ -14,7 +13,7 @@ public function shouldStoreAResponseForAGivenKey() { $cache = new FilesystemCache('/tmp/github-api-test'); - $cache->set('test', new Response); + $cache->set('test', $this->getMock('Github\HttpClient\ResponseInterface')); $this->assertNotNull($cache->get('test')); } @@ -26,7 +25,7 @@ public function shouldGetATimestampForExistingFile() { $cache = new FilesystemCache('/tmp/github-api-test'); - $cache->set('test', new Response); + $cache->set('test', $this->getMock('Github\HttpClient\ResponseInterface')); $this->assertInternalType('int', $cache->getModifiedSince('test')); }