wiki.techinc.nl/includes/http/MwHttpRequestToResponseInterfaceAdapter.php
Michael Große 72f9efd625
Upstream MwHttpRequestToResponseInterfaceAdapter from Wikibase
This makes the PSR-7 interface for the MWHttpRequest available to all
consumers that want to make use of it. This is of general utility and
should not be limited to Wikibase. Also, it allows us to drop the Guzzle
dependency from Wikibase entirely.

As an alternative to moving the adapter (as is done with this patch), it
was considered to refactor MWHttpRequest to support the interface
directly. While that would come without the overhead of an additional
class, it would require adding the interface methods to an already large
class and deprecating the now redundant legacy methods. This would be an
invasive refactoring that would not only affect the classes inheriting
from MWHttpRequest, but also its consumers.

It would seem that a conceptual refactoring of that magnitude would
require a more substantial consensus among contributors (and maybe
consumers) of these classes. Moving this adapter is seen as a step in
building the case for why using standardized interfaces is a good idea
and allowing for the discussion to be grounded of incorporating an existing
adapter into a base class rather than the hypothetical discussion of
adjusting it to an so far unused interface.

Bug: T263989
Depends-On: I56ad52b561460121a8c84313cbd431dc811e2ae1
Change-Id: I2a27dead1d5f1403b8d255c5daf9ba5e7c313476
2020-10-07 10:17:37 +02:00

108 lines
3.2 KiB
PHP

<?php
declare( strict_types = 1 );
namespace MediaWiki\Http;
use LogicException;
use MWHttpRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use function GuzzleHttp\Psr7\stream_for;
/**
* @since 1.36
* @unstable
*
* @license GPL-2.0-or-later
*/
class MwHttpRequestToResponseInterfaceAdapter implements ResponseInterface {
/**
* @var MWHttpRequest
*/
private $mwHttpRequest;
/**
* @param MWHttpRequest $mwHttpRequest the MWHttpRequest must contain response information, i.e. must have been
* `execute`d
*/
public function __construct( MWHttpRequest $mwHttpRequest ) {
$this->validateHasResponse( $mwHttpRequest );
$this->mwHttpRequest = $mwHttpRequest;
}
public function getProtocolVersion(): void {
// This is not accessible via MWHttpRequest, but it is set in its protected `respVersion` property.
// If this is ever needed, it can get exposed in MWHttpRequest.
throw new LogicException( __METHOD__ . ' is not implemented' );
}
public function withProtocolVersion( $version ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function getHeaders(): array {
return $this->mwHttpRequest->getResponseHeaders();
}
public function hasHeader( $name ): bool {
return isset( $this->mwHttpRequest->getResponseHeaders()[$name] );
}
public function getHeader( $name ): array {
return $this->hasHeader( $name ) ? $this->mwHttpRequest->getResponseHeaders()[$name] : [];
}
public function getHeaderLine( $name ): string {
return $this->hasHeader( $name )
? implode( ',', $this->mwHttpRequest->getResponseHeaders()[$name] )
: '';
}
public function withHeader( $name, $value ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function withAddedHeader( $name, $value ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function withoutHeader( $name ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function getBody(): StreamInterface {
return stream_for( $this->mwHttpRequest->getContent() );
}
public function withBody( StreamInterface $body ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function getStatusCode(): int {
return $this->mwHttpRequest->getStatus();
}
public function withStatus( $code, $reasonPhrase = '' ): void {
$this->throwExceptionForBuilderMethod( __METHOD__ );
}
public function getReasonPhrase(): string {
return ''; // not exposed through MWHttpRequest, unlikely to ever be useful
}
private function throwExceptionForBuilderMethod( string $method ): void {
throw new LogicException( "Builder method $method is not supported." );
}
private function validateHasResponse( MWHttpRequest $mwHttpRequest ): void {
/**
* MWHttpRequest objects contain request information, but also contain response information after calling
* `execute`. The best way of determining whether a MWHttpRequest contains response information is to check
* whether its headers list is empty.
*/
if ( empty( $mwHttpRequest->getResponseHeaders() ) ) {
throw new LogicException( 'Trying to get response information from a request that was not yet executed' );
}
}
}