2019-01-30 22:43:28 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\HttpClient ;
2019-10-14 11:53:45 +01:00
use Http\Discovery\Psr17FactoryDiscovery ;
2019-03-28 15:19:14 +00:00
use Nyholm\Psr7\Factory\Psr17Factory ;
2019-06-10 17:27:04 +01:00
use Nyholm\Psr7\Request ;
use Nyholm\Psr7\Uri ;
2019-01-30 22:43:28 +00:00
use Psr\Http\Client\ClientInterface ;
use Psr\Http\Client\NetworkExceptionInterface ;
use Psr\Http\Client\RequestExceptionInterface ;
2019-06-10 17:27:04 +01:00
use Psr\Http\Message\RequestFactoryInterface ;
2019-01-30 22:43:28 +00:00
use Psr\Http\Message\RequestInterface ;
use Psr\Http\Message\ResponseFactoryInterface ;
use Psr\Http\Message\ResponseInterface ;
use Psr\Http\Message\StreamFactoryInterface ;
2019-06-10 17:27:04 +01:00
use Psr\Http\Message\StreamInterface ;
use Psr\Http\Message\UriFactoryInterface ;
use Psr\Http\Message\UriInterface ;
2019-06-30 00:27:41 +01:00
use Symfony\Component\HttpClient\Response\ResponseTrait ;
use Symfony\Component\HttpClient\Response\StreamWrapper ;
2019-01-30 22:43:28 +00:00
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface ;
use Symfony\Contracts\HttpClient\HttpClientInterface ;
2019-06-10 17:27:04 +01:00
if ( ! interface_exists ( RequestFactoryInterface :: class )) {
throw new \LogicException ( 'You cannot use the "Symfony\Component\HttpClient\Psr18Client" as the "psr/http-factory" package is not installed. Try running "composer require nyholm/psr7".' );
}
2019-03-28 15:19:14 +00:00
if ( ! interface_exists ( ClientInterface :: class )) {
throw new \LogicException ( 'You cannot use the "Symfony\Component\HttpClient\Psr18Client" as the "psr/http-client" package is not installed. Try running "composer require psr/http-client".' );
}
2019-01-30 22:43:28 +00:00
/**
* An adapter to turn a Symfony HttpClientInterface into a PSR - 18 ClientInterface .
*
* Run " composer require psr/http-client " to install the base ClientInterface . Run
* " composer require nyholm/psr7 " to install an efficient implementation of response
* and stream factories with flex - provided autowiring aliases .
*
* @ author Nicolas Grekas < p @ tchwork . com >
*/
2019-06-10 17:27:04 +01:00
final class Psr18Client implements ClientInterface , RequestFactoryInterface , StreamFactoryInterface , UriFactoryInterface
2019-01-30 22:43:28 +00:00
{
private $client ;
private $responseFactory ;
private $streamFactory ;
2019-03-28 15:19:14 +00:00
public function __construct ( HttpClientInterface $client = null , ResponseFactoryInterface $responseFactory = null , StreamFactoryInterface $streamFactory = null )
2019-01-30 22:43:28 +00:00
{
2019-03-28 15:19:14 +00:00
$this -> client = $client ? ? HttpClient :: create ();
2019-01-30 22:43:28 +00:00
$this -> responseFactory = $responseFactory ;
2019-03-28 15:19:14 +00:00
$this -> streamFactory = $streamFactory ? ? ( $responseFactory instanceof StreamFactoryInterface ? $responseFactory : null );
if ( null !== $this -> responseFactory && null !== $this -> streamFactory ) {
return ;
}
2019-10-14 11:53:45 +01:00
if ( ! class_exists ( Psr17Factory :: class ) && ! class_exists ( Psr17FactoryDiscovery :: class )) {
2019-03-28 15:19:14 +00:00
throw new \LogicException ( 'You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".' );
}
2019-10-14 11:53:45 +01:00
$psr17Factory = class_exists ( Psr17Factory :: class , false ) ? new Psr17Factory () : null ;
$this -> responseFactory = $this -> responseFactory ? ? $psr17Factory ? ? Psr17FactoryDiscovery :: findResponseFactory ();
$this -> streamFactory = $this -> streamFactory ? ? $psr17Factory ? ? Psr17FactoryDiscovery :: findStreamFactory ();
2019-01-30 22:43:28 +00:00
}
2019-06-10 17:27:04 +01:00
/**
* { @ inheritdoc }
*/
2019-01-30 22:43:28 +00:00
public function sendRequest ( RequestInterface $request ) : ResponseInterface
{
try {
2019-07-23 19:48:28 +01:00
$body = $request -> getBody ();
if ( $body -> isSeekable ()) {
$body -> seek ( 0 );
}
2019-01-30 22:43:28 +00:00
$response = $this -> client -> request ( $request -> getMethod (), ( string ) $request -> getUri (), [
'headers' => $request -> getHeaders (),
2019-07-23 19:48:28 +01:00
'body' => $body -> getContents (),
2019-01-30 22:43:28 +00:00
'http_version' => '1.0' === $request -> getProtocolVersion () ? '1.0' : null ,
]);
$psrResponse = $this -> responseFactory -> createResponse ( $response -> getStatusCode ());
2019-06-10 18:33:26 +01:00
foreach ( $response -> getHeaders ( false ) as $name => $values ) {
2019-01-30 22:43:28 +00:00
foreach ( $values as $value ) {
$psrResponse = $psrResponse -> withAddedHeader ( $name , $value );
}
}
2019-07-16 07:40:46 +01:00
$body = isset ( class_uses ( $response )[ ResponseTrait :: class ]) ? $response -> toStream ( false ) : StreamWrapper :: createResource ( $response , $this -> client );
2019-07-24 15:49:41 +01:00
$body = $this -> streamFactory -> createStreamFromResource ( $body );
2019-07-23 19:48:28 +01:00
if ( $body -> isSeekable ()) {
$body -> seek ( 0 );
}
2019-06-30 00:27:41 +01:00
2019-07-23 19:48:28 +01:00
return $psrResponse -> withBody ( $body );
2019-01-30 22:43:28 +00:00
} catch ( TransportExceptionInterface $e ) {
if ( $e instanceof \InvalidArgumentException ) {
throw new Psr18RequestException ( $e , $request );
}
throw new Psr18NetworkException ( $e , $request );
}
}
2019-06-10 17:27:04 +01:00
/**
* { @ inheritdoc }
*/
public function createRequest ( string $method , $uri ) : RequestInterface
{
if ( $this -> responseFactory instanceof RequestFactoryInterface ) {
return $this -> responseFactory -> createRequest ( $method , $uri );
}
2019-10-14 11:53:45 +01:00
if ( class_exists ( Request :: class )) {
return new Request ( $method , $uri );
2019-06-10 17:27:04 +01:00
}
2019-10-14 11:53:45 +01:00
if ( class_exists ( Psr17FactoryDiscovery :: class )) {
return Psr17FactoryDiscovery :: findRequestFactory () -> createRequest ( $method , $uri );
}
throw new \LogicException ( sprintf ( 'You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".' , __METHOD__ ));
2019-06-10 17:27:04 +01:00
}
/**
* { @ inheritdoc }
*/
public function createStream ( string $content = '' ) : StreamInterface
{
2019-07-23 20:13:48 +01:00
$stream = $this -> streamFactory -> createStream ( $content );
if ( $stream -> isSeekable ()) {
$stream -> seek ( 0 );
}
return $stream ;
2019-06-10 17:27:04 +01:00
}
/**
* { @ inheritdoc }
*/
public function createStreamFromFile ( string $filename , string $mode = 'r' ) : StreamInterface
{
return $this -> streamFactory -> createStreamFromFile ( $filename , $mode );
}
/**
* { @ inheritdoc }
*/
public function createStreamFromResource ( $resource ) : StreamInterface
{
return $this -> streamFactory -> createStreamFromResource ( $resource );
}
/**
* { @ inheritdoc }
*/
public function createUri ( string $uri = '' ) : UriInterface
{
if ( $this -> responseFactory instanceof UriFactoryInterface ) {
return $this -> responseFactory -> createUri ( $uri );
}
2019-10-14 11:53:45 +01:00
if ( class_exists ( Uri :: class )) {
return new Uri ( $uri );
}
if ( class_exists ( Psr17FactoryDiscovery :: class )) {
return Psr17FactoryDiscovery :: findUrlFactory () -> createUri ( $uri );
2019-06-10 17:27:04 +01:00
}
2019-10-14 11:53:45 +01:00
throw new \LogicException ( sprintf ( 'You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".' , __METHOD__ ));
2019-06-10 17:27:04 +01:00
}
2019-01-30 22:43:28 +00:00
}
/**
* @ internal
*/
2019-12-18 15:09:02 +00:00
class Psr18NetworkException extends \RuntimeException implements NetworkExceptionInterface
2019-01-30 22:43:28 +00:00
{
private $request ;
public function __construct ( TransportExceptionInterface $e , RequestInterface $request )
{
parent :: __construct ( $e -> getMessage (), 0 , $e );
$this -> request = $request ;
}
public function getRequest () : RequestInterface
{
return $this -> request ;
}
}
/**
* @ internal
*/
class Psr18RequestException extends \InvalidArgumentException implements RequestExceptionInterface
{
2019-12-18 15:09:02 +00:00
private $request ;
public function __construct ( TransportExceptionInterface $e , RequestInterface $request )
{
parent :: __construct ( $e -> getMessage (), 0 , $e );
$this -> request = $request ;
}
public function getRequest () : RequestInterface
{
return $this -> request ;
}
2019-01-30 22:43:28 +00:00
}