Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace PHP-HTTP usage with PSR-17 #15

Merged
merged 1 commit into from
Nov 15, 2023
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
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. <[email protected]>
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 <[email protected]>
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