Skip to content

Commit

Permalink
Replace PHP-HTTP usage with PSR-17
Browse files Browse the repository at this point in the history
  • Loading branch information
glaubinix committed Nov 15, 2023
1 parent cc8f9dc commit 2a313e8
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 68 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 2.2.0 / Unreleased
### Added:
### Changed:
- Uses PSR-17 internally instead of the deprecated PHP-HTTP `MessageFactory`
### Deprecated:
- Usage of `Api:api` with not fully qualified class name
- Usage of `Api::HTTP_RESPONSE_*` constants
- Usage of response format other than `json`
- Passing a string as `$params` to the methods `create` and `update` of the `PullRequests`, `BranchRestrictions`, `Pipelines`, and `Repository` API
- `ClientInterface`, use `Client` instead
- Passing a string as `$params` to the `request` method of `Client`
- Usage of `Client::getMessageFactory` use `Client::getRequestFactory` instead
- Passing `Http\Message\MessageFactory` to `HttpPluginClientBuilder`

## 2.1.0 / 2021-07-23

Expand Down
13 changes: 10 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@
"php-http/discovery": "^1.0",
"php-http/client-implementation": "^1.0",
"php-http/client-common": "^2.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
"symfony/deprecation-contracts": "^2.2 || ^3.0",
"psr/http-factory-implementation": "^1.0"
},
"require-dev": {
"phpunit/phpunit":"^7.5|^8|^9",
"php-http/mock-client": " ^1.2",
"squizlabs/php_codesniffer": "^3.5",
"php-http/guzzle6-adapter": "^2.0",
"phpstan/phpstan": "^0.12.90|^1"
"phpstan/phpstan": "^0.12.90|^1",
"nyholm/psr7": "^1.6.1",
"php-http/message-factory": "^1.0"
},
"replace": {
"gentle/bitbucket-api": "*"
Expand All @@ -53,5 +55,10 @@
"scripts": {
"style": "php vendor/bin/phpcs --standard=psr2 lib/ test --ignore=*/HistoryVersionBridge.php",
"test": "php vendor/bin/phpunit"
},
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
}
26 changes: 18 additions & 8 deletions lib/Bitbucket/API/Http/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
use Bitbucket\API\Http\Plugin\HistoryPlugin;
use Http\Client\Common\HttpMethodsClient;
use Http\Client\Common\Plugin;
use Http\Discovery\UriFactoryDiscovery;
use Http\Message\MessageFactory;
use Http\Discovery\Psr17FactoryDiscovery;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* @author Alexandru G. <alex@gentle.ro>
Expand All @@ -40,8 +41,10 @@ class Client implements ClientInterface

/** @var HttpPluginClientBuilder */
private $httpClientBuilder;
/** @var MessageFactory */
private $messageFactory;
/** @var RequestFactoryInterface */
private $requestFactory;
/** @var StreamFactoryInterface */
private $streamFactory;
/** @var HistoryPlugin */
private $responseHistory;

Expand All @@ -55,7 +58,7 @@ public function __construct(array $options = array(), HttpPluginClientBuilder $h
$this->httpClientBuilder = $httpClientBuilder ?: new HttpPluginClientBuilder();

$this->httpClientBuilder->addPlugin(
new Plugin\AddHostPlugin(UriFactoryDiscovery::find()->createUri($this->options['base_url']))
new Plugin\AddHostPlugin(Psr17FactoryDiscovery::findUriFactory()->createUri($this->options['base_url']))
);
$this->httpClientBuilder->addPlugin(new Plugin\RedirectPlugin());
$this->httpClientBuilder->addPlugin(new Plugin\HeaderDefaultsPlugin([
Expand All @@ -65,7 +68,8 @@ public function __construct(array $options = array(), HttpPluginClientBuilder $h

$this->setApiVersion($this->options['api_version']);

$this->messageFactory = $this->httpClientBuilder->getMessageFactory();
$this->requestFactory = $this->httpClientBuilder->getRequestFactory();
$this->streamFactory = Psr17FactoryDiscovery::findStreamFactory();
}

/**
Expand Down Expand Up @@ -124,7 +128,7 @@ public function request($endpoint, $params = array(), $method = 'GET', array $he
}
}

$body = null;
$body = '';
if (is_string($paramsString) && $paramsString !== null) {
$body = $paramsString;
}
Expand All @@ -140,7 +144,13 @@ public function request($endpoint, $params = array(), $method = 'GET', array $he
$endpoint .= (strpos($endpoint, '?') === false ? '?' : '&').'format='.$this->getResponseFormat();
}

$request = $this->messageFactory->createRequest($method, $endpoint, $headers, $body);
$request = $this->requestFactory
->createRequest($method, $endpoint)
->withBody($this->streamFactory->createStream($body));

foreach ($headers as $name => $value) {
$request = $request->withHeader($name, $value);
}

return $this->getClient()->sendRequest($request);
}
Expand Down
62 changes: 52 additions & 10 deletions lib/Bitbucket/API/Http/HttpPluginClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,56 @@
use Http\Client\Common\HttpMethodsClient;
use Http\Client\Common\Plugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpClient;
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Discovery\Psr18ClientDiscovery;
use Http\Message\MessageFactory;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;

class HttpPluginClientBuilder
{
/** @var HttpClient */
/** @var ClientInterface */
private $httpClient;
/** @var HttpMethodsClient|null */
private $pluginClient;
/** @var MessageFactory */
private $messageFactory;
/** @var MessageFactory|RequestFactoryInterface */
private $requestFactory;
/** @var StreamFactoryInterface */
private $streamFactory;
/** @var Plugin[] */
private $plugins = [];

public function __construct(HttpClient $httpClient = null, MessageFactory $messageFactory = null)
/**
* @param MessageFactory|RequestFactoryInterface|null $requestFactory
*/
public function __construct(ClientInterface $httpClient = null, $requestFactory = null, StreamFactoryInterface $streamFactory = null)
{
$this->httpClient = $httpClient ?: HttpClientDiscovery::find();
$this->messageFactory = $messageFactory ?: MessageFactoryDiscovery::find();
$requestFactory = $requestFactory ?? Psr17FactoryDiscovery::findRequestFactory();
if ($requestFactory instanceof MessageFactory) {
// Use same format as symfony/deprecation-contracts.
@trigger_error(sprintf(
'Since %s %s: %s is deprecated, use %s instead.',
'private-packagist/bitbucket-api',
'2.2.0',
'\Http\Message\MessageFactory',
RequestFactoryInterface::class
), \E_USER_DEPRECATED);
} elseif (!$requestFactory instanceof RequestFactoryInterface) {
/** @var mixed $requestFactory value unknown; set to mixed, prevent PHPStan complaining about guard clauses */
throw new \TypeError(sprintf(
'%s::__construct(): Argument #2 ($requestFactory) must be of type %s|%s, %s given',
self::class,
'\Http\Message\MessageFactory',
RequestFactoryInterface::class,
is_object($requestFactory) ? get_class($requestFactory) : gettype($requestFactory)
));
}

$this->httpClient = $httpClient ?: Psr18ClientDiscovery::find();
$this->requestFactory = $requestFactory;
$this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory();
}

/**
Expand Down Expand Up @@ -79,7 +109,8 @@ public function getHttpClient()
if (!$this->pluginClient) {
$this->pluginClient = new HttpMethodsClient(
new PluginClient($this->httpClient, $this->plugins),
$this->messageFactory
$this->requestFactory,
$this->streamFactory
);
}

Expand All @@ -88,9 +119,20 @@ public function getHttpClient()

/**
* @return MessageFactory
* @deprecated Use getRequestFactory instead. message will be removed with 3.0
*/
public function getMessageFactory()
{
return $this->messageFactory;
return $this->requestFactory instanceof MessageFactory
? $this->requestFactory
: MessageFactoryDiscovery::find();
}

/**
* @return RequestFactoryInterface
*/
public function getRequestFactory()
{
return $this->requestFactory;
}
}
25 changes: 12 additions & 13 deletions lib/Bitbucket/API/Http/Plugin/ApiOneCollectionPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
namespace Bitbucket\API\Http\Plugin;

use Http\Client\Common\Plugin;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\ResponseFactory;
use Http\Discovery\Psr17FactoryDiscovery;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* Helper for `Pager`
Expand All @@ -28,8 +28,8 @@ class ApiOneCollectionPlugin implements Plugin
{
use Plugin\VersionBridgePlugin;

/** @var ResponseFactory */
private $responseFactory;
/** @var StreamFactoryInterface */
private $streamFactory;

/** @var array */
private $urlQueryComponents;
Expand All @@ -40,9 +40,13 @@ class ApiOneCollectionPlugin implements Plugin
/** @var array */
private $content;

public function __construct(ResponseFactory $responseFactory = null)
/**
* @param object|null $responseFactory This argument is deprecated and will be removed in 3.0
*/
public function __construct($responseFactory = null)
{
$this->responseFactory = $responseFactory ?: MessageFactoryDiscovery::find();
$this->streamFactory = Psr17FactoryDiscovery::findStreamFactory();
unset($responseFactory);
}

/**
Expand All @@ -61,13 +65,8 @@ protected function doHandleRequest(RequestInterface $request, callable $next, ca
$request
);

return $this->responseFactory->createResponse(
$response->getStatusCode(),
$response->getReasonPhrase(),
$response->getHeaders(),
json_encode($content),
$response->getProtocolVersion()
);
return $response
->withBody($this->streamFactory->createStream(json_encode($content)));
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/Bitbucket/API/Http/Plugin/ApiVersionPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Http\Client\Common\Plugin;
use Http\Promise\Promise;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

class ApiVersionPlugin implements Plugin
{
Expand All @@ -26,7 +27,7 @@ public function __construct($version)
* @param callable $next Next middleware in the chain, the request is passed as the first argument
* @param callable $first First middleware in the chain, used to to restart a request
*
* @return Promise Resolves a PSR-7 Response or fails with an Http\Client\Exception (The same as HttpAsyncClient).
* @return Promise<ResponseInterface> Resolves a PSR-7 Response or fails with an Http\Client\Exception (The same as HttpAsyncClient).
*/
protected function doHandleRequest(RequestInterface $request, callable $next, callable $first)
{
Expand Down
28 changes: 14 additions & 14 deletions lib/Bitbucket/API/Http/Response/Pager.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
namespace Bitbucket\API\Http\Response;

use Bitbucket\API\Http\HttpPluginClientBuilder;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\MessageFactory;
use Http\Discovery\Psr17FactoryDiscovery;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* @author Alexandru Guzinschi <alex@gentle.ro>
Expand All @@ -21,22 +21,24 @@ class Pager implements PagerInterface
{
/** @var HttpPluginClientBuilder */
private $httpPluginClientBuilder;
/** @var MessageFactory */
private $messageFactory;
/** @var StreamFactoryInterface */
private $streamFactory;
/** @var ResponseInterface */
private $response;

/**
* @param HttpPluginClientBuilder $httpPluginClientBuilder
* @param ResponseInterface $response
* @param MessageFactory $messageFactory
* @param object|null $messageFactory This argument is deprecated and will be removed in 3.0.0
* @param StreamFactoryInterface|null $streamFactory
*
* @throws \UnexpectedValueException
*/
public function __construct(
HttpPluginClientBuilder $httpPluginClientBuilder,
ResponseInterface $response,
MessageFactory $messageFactory = null
$messageFactory = null,
StreamFactoryInterface $streamFactory = null
) {
/** @var ResponseInterface $response */
if ($response->getStatusCode() >= 400) {
Expand All @@ -45,7 +47,9 @@ public function __construct(

$this->httpPluginClientBuilder = $httpPluginClientBuilder;
$this->response = $response;
$this->messageFactory = $messageFactory ? : MessageFactoryDiscovery::find();
$this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();

unset($messageFactory);
}

/**
Expand Down Expand Up @@ -117,13 +121,9 @@ public function fetchAll()
}

$content['values'] = $values;
$this->response = $this->messageFactory->createResponse(
$this->response->getStatusCode(),
$this->response->getReasonPhrase(),
$this->response->getHeaders(),
json_encode($content),
$this->response->getProtocolVersion()
);

$this->response = $this->response
->withBody($this->streamFactory->createStream(json_encode($content)));

return $this->response;
}
Expand Down
Loading

0 comments on commit 2a313e8

Please sign in to comment.