Skip to content
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/vendor/
/composer.lock
/composer.lock
.idea
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
}
],
"require": {
"php": ">=5.4.0",
"guzzlehttp/guzzle": ">=5.3 <7.0"
"php": "^7.2|^8.0",
"guzzlehttp/guzzle": "~7.0",
"guzzlehttp/uri-template": "0.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.8.*"
"phpunit/phpunit": "^9.0"
},
"autoload": {
"psr-4": {
Expand All @@ -26,4 +27,4 @@
"HapiClient\\Tests\\": "tests/"
}
}
}
}
77 changes: 38 additions & 39 deletions src/Http/HapiClient.php
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
<?php
namespace HapiClient\Http;

use GuzzleHttp\UriTemplate\UriTemplate;
use HapiClient\Http\Auth\AuthenticationMethod;
use HapiClient\Hal\ResourceInterface;
use HapiClient\Hal\Resource;
use HapiClient\Hal\RegisteredRel;
use HapiClient\Exception;
use HapiClient\Util\Misc;
use \GuzzleHttp\Client;
use \GuzzleHttp\ClientInterface;
use \GuzzleHttp\UriTemplate;

final class HapiClient implements HapiClientInterface
{
private $apiUrl;
private $entryPointUrl;
private $profile;
private $authenticationMethod;

private $client;

private $entryPointResource;

/**
* @param $apiUrl string The URL pointing to the API server.
* @param $entryPointUrl string The URL to the entry point Resource.
Expand All @@ -42,10 +41,10 @@ public function __construct(
$this->entryPointUrl = trim($entryPointUrl);
$this->profile = trim($profile);
$this->authenticationMethod = $authenticationMethod;

if ($this->apiUrl) {
$baseUrl = rtrim($this->apiUrl, '/') . '/';

if (Misc::isGuzzle6()) {
$this->client = new Client(['base_uri' => $baseUrl]);
} else {
Expand All @@ -55,54 +54,54 @@ public function __construct(
$this->client = new Client();
}
}

/**
* {@inheritDoc}
*/
public function getApiUrl()
{
return $this->apiUrl;
}

/**
* {@inheritDoc}
*/
public function getEntryPointUrl()
{
return $this->entryPointUrl;
}

/**
* {@inheritDoc}
*/
public function getProfile()
{
return $this->profile;
}

/**
* {@inheritDoc}
*/
public function getAuthenticationMethod()
{
return $this->authenticationMethod;
}

/**
* {@inheritDoc}
*/
public function &getClient()
{
return $this->client;
}

/**
* The magic setter is overridden to insure immutability.
*/
final public function __set($name, $value)
{
}

/**
* {@inheritDoc}
*/
Expand All @@ -112,34 +111,34 @@ public function sendRequest(RequestInterface $request)
$options = [];
if (Misc::isGuzzle6()) {
$options['exceptions'] = false;

if (($verify = Misc::verify($request->getUrl(), __DIR__ . '/../CA/')) !== null) {
$options['verify'] = $verify;
}
}

// Create the HTTP request
$httpRequest = $this->createHttpRequest($request);

// Send the request
$httpResponse = $this->client->send($httpRequest, $options);

// If Unauthorized, maybe the authorization just timed out.
// Try it again to be sure.
if ($httpResponse->getStatusCode() == 401 && $this->authenticationMethod != null) {
// Create the HTTP request (and Authorize again)
$httpRequest = $this->createHttpRequest($request);

// Execute again
$httpResponse = $this->client->send($httpRequest, $options);
}

// Check the status code (must be 2xx)
$statusCode = $httpResponse->getStatusCode();
if ($statusCode >= 200 && $statusCode < 300) {
return Resource::fromJson((string) $httpResponse->getBody());
}

// Exception depending on status code for 3xx, 4xx and 5xx
if ($statusCode >= 300 && $statusCode < 400) {
throw new Exception\HttpRedirectionException($httpRequest, $httpResponse);
Expand All @@ -151,7 +150,7 @@ public function sendRequest(RequestInterface $request)
throw new Exception\HttpException($httpRequest, $httpResponse);
}
}

/**
* {@inheritDoc}
*/
Expand All @@ -160,11 +159,11 @@ public function sendFollow($follow, ResourceInterface $resource = null)
if (!$resource) {
$resource = $this->getEntryPointResource();
}

if (!is_array($follow)) {
$follow = array($follow);
}

foreach ($follow as $hop) {
$resource = $this->sendRequest(new Request(
$hop->getUrl($resource),
Expand All @@ -174,7 +173,7 @@ public function sendFollow($follow, ResourceInterface $resource = null)
$hop->getHeaders()
));
}

return $resource;
}

Expand All @@ -186,10 +185,10 @@ public function getEntryPointResource()
if ($this->entryPointResource) {
return $this->entryPointResource;
}

return $this->entryPointResource = $this->sendRequest(new Request($this->entryPointUrl));
}

/**
* {@inheritDoc}
*/
Expand All @@ -202,7 +201,7 @@ public function refresh($resource)
return $resource;
}
}

/**
* Instantiates the HttpRequest depending on the
* configuration from the given Request.
Expand All @@ -215,34 +214,34 @@ private function createHttpRequest(RequestInterface $request)
if ($this->authenticationMethod) {
$request = $this->authenticationMethod->authorizeRequest($this, $request);
}

// The URL
$url = ltrim(trim($request->getUrl()), '/');

// Handle templated URLs
if ($urlVariables = $request->getUrlVariables()) {
$url = (new UriTemplate())->expand($url, $urlVariables);
}

// Headers
$headers = [];
$headersToAdd = $request->getHeaders();

// The message body
$body = null;
if ($messageBody = $request->getMessageBody()) {
$headers['Content-Type'] = $messageBody->getContentType();
$headers['Content-Length'] = $messageBody->getContentLength();
$body = $messageBody->getContent();
}

// Accept hal+json response
if ($this->profile) {
$headers['Accept'] = 'application/hal+json; profile="' . $this->profile . '"';
} else {
$headers['Accept'] = 'application/json';
}

// Prepare the Guzzle request
if (Misc::isGuzzle6()) {
// Guzzle 6
Expand All @@ -255,25 +254,25 @@ private function createHttpRequest(RequestInterface $request)
} else {
// Guzzle 5.3
$httpRequest = $this->client->createRequest($request->getMethod(), $url, ['exceptions' => false]);

// verify option for HTTPS requests if needed
if (($verify = Misc::verify($url, __DIR__ . '/../CA/')) !== null) {
$httpRequest->getConfig()->set('verify', $verify);
}

foreach ($headers as $key => $value) {
$httpRequest->setHeader($key, $value);
}

foreach ($headersToAdd as $key => $value) {
$httpRequest->setHeader($key, $value);
}

if ($body) {
$httpRequest->setBody(\GuzzleHttp\Stream\Stream::factory($body));
}
}

return $httpRequest;
}
}
5 changes: 3 additions & 2 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<?php
namespace HapiClient\tests;
namespace HapiClient\Tests;

use HapiClient\Http;
use HapiClient\Http\Auth;
use HapiClient\Hal;
use HapiClient\Exception;
use PHPUnit\Framework\TestCase;

class ClientTest extends \PHPUnit_Framework_TestCase
class ClientTest extends TestCase
{
const APIURL = 'https://api.preprod.slimpay.com';
const PROFILEURL = 'https://api.slimpay.net/alps/v1';
Expand Down
3 changes: 2 additions & 1 deletion tests/ResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
namespace HapiClient\tests;

use HapiClient\Hal;
use PHPUnit\Framework\TestCase;

class ResourceTest extends \PHPUnit_Framework_TestCase
class ResourceTest extends TestCase
{
const JSON_REPRESENTATION = <<<END
{
Expand Down
3 changes: 2 additions & 1 deletion tests/WrongCredentialsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
use HapiClient\Http;
use HapiClient\Http\Auth;
use HapiClient\Exception;
use PHPUnit\Framework\TestCase;

class WrongCredentialsTest extends \PHPUnit_Framework_TestCase
class WrongCredentialsTest extends TestCase
{
const APIURL = 'https://api.preprod.slimpay.com';
const PROFILEURL = 'https://api.slimpay.net/alps/v1';
Expand Down