Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
run: 'echo "::set-output name=cache-dir::$(composer config cache-files-dir)"'

- name: 'Cache dependencies'
uses: 'actions/cache@v2'
uses: 'actions/cache@v4'
with:
path: '${{ steps.composer-cache.outputs.cache-dir }}'
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
"php-http/client-implementation": "^1.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message": "^1.0",
"php-http/message-factory": "^1.0",
"php-xapi/exception": "^1.0",
"php-xapi/model": "^4.0",
"php-xapi/serializer": "^4.0",
"php-xapi/symfony-serializer": "^3.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.0",
"psr/http-factory": "^1.0"
},
"require-dev": {
"phpspec/phpspec": "^6.0 || ^7.0",
Expand Down
72 changes: 49 additions & 23 deletions spec/Request/HandlerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace spec\Xabbuh\XApi\Client\Request;

use Http\Client\HttpClient;
use Http\Message\RequestFactory;
use PhpSpec\ObjectBehavior;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Xabbuh\XApi\Common\Exception\AccessDeniedException;
Expand All @@ -14,7 +14,7 @@

class HandlerSpec extends ObjectBehavior
{
function let(HttpClient $client, RequestFactory $requestFactory)
function let(ClientInterface $client, RequestFactoryInterface $requestFactory)
{
$this->beConstructedWith($client, $requestFactory, 'http://example.com/xapi/', '1.0.1');
}
Expand All @@ -24,8 +24,10 @@ function it_throws_an_exception_if_a_request_is_created_with_an_invalid_method()
$this->shouldThrow('\InvalidArgumentException')->during('createRequest', array('options', '/xapi/statements'));
}

function it_returns_get_request_created_by_the_http_client(RequestFactory $requestFactory, RequestInterface $request)
{
function it_returns_get_request_created_by_the_http_client(
RequestFactoryInterface $requestFactory,
RequestInterface $request
) {
$requestFactory->createRequest('GET', 'http://example.com/xapi/statements', array(
'X-Experience-API-Version' => '1.0.1',
'Content-Type' => 'application/json',
Expand All @@ -35,8 +37,10 @@ function it_returns_get_request_created_by_the_http_client(RequestFactory $reque
$this->createRequest('GET', '/statements')->shouldReturn($request);
}

function it_returns_post_request_created_by_the_http_client(RequestFactory $requestFactory, RequestInterface $request)
{
function it_returns_post_request_created_by_the_http_client(
RequestFactoryInterface $requestFactory,
RequestInterface $request
) {
$requestFactory->createRequest('POST', 'http://example.com/xapi/statements', array(
'X-Experience-API-Version' => '1.0.1',
'Content-Type' => 'application/json',
Expand All @@ -46,8 +50,10 @@ function it_returns_post_request_created_by_the_http_client(RequestFactory $requ
$this->createRequest('POST', '/statements', array(), 'body')->shouldReturn($request);
}

function it_returns_put_request_created_by_the_http_client(RequestFactory $requestFactory, RequestInterface $request)
{
function it_returns_put_request_created_by_the_http_client(
RequestFactoryInterface $requestFactory,
RequestInterface $request
) {
$requestFactory->createRequest('PUT', 'http://example.com/xapi/statements', array(
'X-Experience-API-Version' => '1.0.1',
'Content-Type' => 'application/json',
Expand All @@ -57,8 +63,10 @@ function it_returns_put_request_created_by_the_http_client(RequestFactory $reque
$this->createRequest('PUT', '/statements', array(), 'body')->shouldReturn($request);
}

function it_returns_delete_request_created_by_the_http_client(RequestFactory $requestFactory, RequestInterface $request)
{
function it_returns_delete_request_created_by_the_http_client(
RequestFactoryInterface $requestFactory,
RequestInterface $request
) {
$requestFactory->createRequest('DELETE', 'http://example.com/xapi/statements', array(
'X-Experience-API-Version' => '1.0.1',
'Content-Type' => 'application/json',
Expand All @@ -68,53 +76,71 @@ function it_returns_delete_request_created_by_the_http_client(RequestFactory $re
$this->createRequest('DELETE', '/statements')->shouldReturn($request);
}

function it_throws_an_access_denied_exception_when_a_401_status_code_is_returned(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_throws_an_access_denied_exception_when_a_401_status_code_is_returned(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(401);
$response->getBody()->willReturn('body');

$this->shouldThrow(AccessDeniedException::class)->during('executeRequest', array($request, array(200)));
}

function it_throws_an_access_denied_exception_when_a_403_status_code_is_returned(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_throws_an_access_denied_exception_when_a_403_status_code_is_returned(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(403);
$response->getBody()->willReturn('body');

$this->shouldThrow(AccessDeniedException::class)->during('executeRequest', array($request, array(200)));
}

function it_throws_a_not_found_exception_when_a_404_status_code_is_returned(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_throws_a_not_found_exception_when_a_404_status_code_is_returned(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(404);
$response->getBody()->willReturn('body');

$this->shouldThrow(NotFoundException::class)->during('executeRequest', array($request, array(200)));
}

function it_throws_a_conflict_exception_when_a_409_status_code_is_returned(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_throws_a_conflict_exception_when_a_409_status_code_is_returned(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(409);
$response->getBody()->willReturn('body');

$this->shouldThrow(ConflictException::class)->during('executeRequest', array($request, array(200)));
}

function it_throws_an_xapi_exception_when_an_unexpected_status_code_is_returned(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_throws_an_xapi_exception_when_an_unexpected_status_code_is_returned(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(204);
$response->getBody()->willReturn('body');

$this->shouldThrow(XApiException::class)->during('executeRequest', array($request, array(200)));
}

function it_returns_the_response_on_success(HttpClient $client, RequestInterface $request, ResponseInterface $response)
{
function it_returns_the_response_on_success(
ClientInterface $client,
RequestInterface $request,
ResponseInterface $response
) {
$client->sendRequest($request)->willReturn($response);
$response->getStatusCode()->willReturn(200);
$response->getBody()->willReturn('body');
Expand Down
60 changes: 41 additions & 19 deletions spec/XApiClientBuilderSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace spec\Xabbuh\XApi\Client;

use Http\Client\HttpClient;
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\RequestFactory;
use PhpSpec\Exception\Example\SkippingException;
use PhpSpec\ObjectBehavior;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Xabbuh\Http\Authentication\OAuth1;
use Xabbuh\XApi\Client\XApiClientBuilderInterface;
use Xabbuh\XApi\Client\XApiClientInterface;
Expand All @@ -19,15 +19,15 @@ function it_is_an_xapi_client_builder()
$this->shouldHaveType(XApiClientBuilderInterface::class);
}

function it_creates_an_xapi_client(HttpClient $httpClient, RequestFactory $requestFactory)
function it_creates_an_xapi_client(ClientInterface $httpClient, RequestFactoryInterface $requestFactory)
{
$this->setHttpClient($httpClient);
$this->setRequestFactory($requestFactory);
$this->setBaseUrl('http://example.com/xapi/');
$this->build()->shouldHaveType(XApiClientInterface::class);
}

function its_methods_can_be_chained(HttpClient $httpClient, RequestFactory $requestFactory)
function its_methods_can_be_chained(ClientInterface $httpClient, RequestFactoryInterface $requestFactory)
{
$this->setHttpClient($httpClient)->shouldReturn($this);
$this->setRequestFactory($requestFactory)->shouldReturn($this);
Expand All @@ -37,10 +37,12 @@ function its_methods_can_be_chained(HttpClient $httpClient, RequestFactory $requ
$this->setOAuthCredentials('consumer key', 'consumer secret', 'token', 'token secret')->shouldReturn($this);
}

function it_throws_an_exception_if_the_http_client_is_not_configured(RequestFactory $requestFactory)
function it_throws_an_exception_if_the_http_client_is_not_configured(RequestFactoryInterface $requestFactory)
{
if ($this->isAbleToDiscoverHttpClient()) {
throw new SkippingException('The builder does not throw an exception if it can automatically discover an HTTP client.');
throw new SkippingException(
'The builder does not throw an exception if it can automatically discover an HTTP client.'
);
}

$this->setRequestFactory($requestFactory);
Expand All @@ -49,10 +51,12 @@ function it_throws_an_exception_if_the_http_client_is_not_configured(RequestFact
$this->shouldThrow('\LogicException')->during('build');
}

function it_throws_an_exception_if_the_request_factory_is_not_configured(HttpClient $httpClient)
function it_throws_an_exception_if_the_request_factory_is_not_configured(ClientInterface $httpClient)
{
if ($this->isAbleToDiscoverRequestFactory()) {
throw new SkippingException('The builder does not throw an exception if it can automatically discover a request factory.');
throw new SkippingException(
'The builder does not throw an exception if it can automatically discover a request factory.'
);
}

$this->setHttpClient($httpClient);
Expand All @@ -61,10 +65,16 @@ function it_throws_an_exception_if_the_request_factory_is_not_configured(HttpCli
$this->shouldThrow('\LogicException')->during('build');
}

function it_can_build_the_client_when_it_is_able_to_discover_the_http_client_and_the_request_factory_without_configuring_them_explicitly()
function it_can_build_the_client_when_it_is_able_to_discover_the_http_client_and_the_request_factory_without_configuring_them_explicitly(
)
{
if (!class_exists(HttpClientDiscovery::class)) {
throw new SkippingException(sprintf('The "%s" class is required to let the builder auto discover the HTTP client and request factory.', HttpClientDiscovery::class));
throw new SkippingException(
sprintf(
'The "%s" class is required to let the builder auto discover the HTTP client and request factory.',
HttpClientDiscovery::class
)
);
}

if (!$this->isAbleToDiscoverHttpClient()) {
Expand All @@ -80,32 +90,44 @@ function it_can_build_the_client_when_it_is_able_to_discover_the_http_client_and
$this->build()->shouldReturnAnInstanceOf(XApiClientInterface::class);
}

function it_throws_an_exception_if_the_base_uri_is_not_configured(HttpClient $httpClient, RequestFactory $requestFactory)
{
function it_throws_an_exception_if_the_base_uri_is_not_configured(
ClientInterface $httpClient,
RequestFactoryInterface $requestFactory
) {
$this->setHttpClient($httpClient);
$this->setRequestFactory($requestFactory);

$this->shouldThrow('\LogicException')->during('build');
}

function it_throws_an_exception_when_oauth_credentials_are_configured_but_the_auth_package_is_missing(HttpClient $httpClient, RequestFactory $requestFactory)
{
function it_throws_an_exception_when_oauth_credentials_are_configured_but_the_auth_package_is_missing(
ClientInterface $httpClient,
RequestFactoryInterface $requestFactory
) {
if (class_exists(OAuth1::class)) {
throw new SkippingException('OAuth1 credentials can be used when the "xabbuh/oauth1-authentication" package is present.');
throw new SkippingException(
'OAuth1 credentials can be used when the "xabbuh/oauth1-authentication" package is present.'
);
}

$this->setHttpClient($httpClient);
$this->setRequestFactory($requestFactory);
$this->setBaseUrl('http://example.com/xapi/');
$this->setOAuthCredentials('consumer_key', 'consumer_secret', 'access_token', 'token_secret');

$this->shouldThrow(new \LogicException('The "xabbuh/oauth1-authentication package is needed to use OAuth1 authorization.'))->during('build');
$this->shouldThrow(
new \LogicException('The "xabbuh/oauth1-authentication package is needed to use OAuth1 authorization.')
)->during('build');
}

function it_accepts_oauth_credentials_when_the_auth_package_is_present(HttpClient $httpClient, RequestFactory $requestFactory)
{
function it_accepts_oauth_credentials_when_the_auth_package_is_present(
ClientInterface $httpClient,
RequestFactoryInterface $requestFactory
) {
if (!class_exists(OAuth1::class)) {
throw new SkippingException('OAuth1 credentials cannot be used when the "xabbuh/oauth1-authentication" package is missing.');
throw new SkippingException(
'OAuth1 credentials cannot be used when the "xabbuh/oauth1-authentication" package is missing.'
);
}

$this->setHttpClient($httpClient);
Expand Down
14 changes: 8 additions & 6 deletions src/Request/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Xabbuh\XApi\Client\Request;

use Http\Client\Exception;
use Http\Client\HttpClient;
use Http\Message\RequestFactory;

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Xabbuh\XApi\Common\Exception\AccessDeniedException;
use Xabbuh\XApi\Common\Exception\ConflictException;
Expand All @@ -33,12 +35,12 @@ final class Handler implements HandlerInterface
private $version;

/**
* @param HttpClient $httpClient The HTTP client sending requests to the remote LRS
* @param RequestFactory $requestFactory The factory used to create PSR-7 HTTP requests
* @param string $baseUri The APIs base URI (all end points will be created relatively to this URI)
* @param string $version The xAPI version
* @param ClientInterface $httpClient The HTTP client sending requests to the remote LRS
* @param RequestFactoryInterface $requestFactory The factory used to create PSR-7 HTTP requests
* @param string $baseUri The APIs base URI (all end points will be created relatively to this URI)
* @param string $version The xAPI version
*/
public function __construct(HttpClient $httpClient, RequestFactory $requestFactory, $baseUri, $version)
public function __construct(ClientInterface $httpClient, RequestFactoryInterface $requestFactory, $baseUri, $version)
{
$this->httpClient = $httpClient;
$this->requestFactory = $requestFactory;
Expand Down
12 changes: 6 additions & 6 deletions src/XApiClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
use ApiClients\Tools\Psr7\Oauth1\RequestSigning\RequestSigner;
use Http\Client\Common\Plugin\AuthenticationPlugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpClient;
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\Authentication\BasicAuth;
use Http\Message\RequestFactory;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Xabbuh\Http\Authentication\OAuth1;
use Xabbuh\XApi\Client\Request\Handler;
use Xabbuh\XApi\Serializer\SerializerFactoryInterface;
Expand All @@ -39,12 +39,12 @@ final class XApiClientBuilder implements XApiClientBuilderInterface
private $serializerFactory;

/**
* @var HttpClient|null
* @var ClientInterface|null
*/
private $httpClient;

/**
* @var RequestFactory|null
* @var RequestFactoryInterface|null
*/
private $requestFactory;

Expand All @@ -65,7 +65,7 @@ public function __construct(SerializerFactoryInterface $serializerFactory = null
/**
* {@inheritdoc}
*/
public function setHttpClient(HttpClient $httpClient)
public function setHttpClient(ClientInterface $httpClient)
{
$this->httpClient = $httpClient;

Expand All @@ -75,7 +75,7 @@ public function setHttpClient(HttpClient $httpClient)
/**
* {@inheritdoc}
*/
public function setRequestFactory(RequestFactory $requestFactory)
public function setRequestFactory(RequestFactoryInterface $requestFactory)
{
$this->requestFactory = $requestFactory;

Expand Down
Loading
Loading