vendor/symfony/http-client/Response/CommonResponseTrait.php line 132

  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\HttpClient\Response;
  11. use Symfony\Component\HttpClient\Exception\ClientException;
  12. use Symfony\Component\HttpClient\Exception\JsonException;
  13. use Symfony\Component\HttpClient\Exception\RedirectionException;
  14. use Symfony\Component\HttpClient\Exception\ServerException;
  15. use Symfony\Component\HttpClient\Exception\TransportException;
  16. /**
  17.  * Implements common logic for response classes.
  18.  *
  19.  * @author Nicolas Grekas <p@tchwork.com>
  20.  *
  21.  * @internal
  22.  */
  23. trait CommonResponseTrait
  24. {
  25.     /**
  26.      * @var callable|null A callback that tells whether we're waiting for response headers
  27.      */
  28.     private $initializer;
  29.     private $shouldBuffer;
  30.     private $content;
  31.     private int $offset 0;
  32.     private ?array $jsonData null;
  33.     public function getContent(bool $throw true): string
  34.     {
  35.         if ($this->initializer) {
  36.             self::initialize($this);
  37.         }
  38.         if ($throw) {
  39.             $this->checkStatusCode();
  40.         }
  41.         if (null === $this->content) {
  42.             $content null;
  43.             foreach (self::stream([$this]) as $chunk) {
  44.                 if (!$chunk->isLast()) {
  45.                     $content .= $chunk->getContent();
  46.                 }
  47.             }
  48.             if (null !== $content) {
  49.                 return $content;
  50.             }
  51.             if (null === $this->content) {
  52.                 throw new TransportException('Cannot get the content of the response twice: buffering is disabled.');
  53.             }
  54.         } else {
  55.             foreach (self::stream([$this]) as $chunk) {
  56.                 // Chunks are buffered in $this->content already
  57.             }
  58.         }
  59.         rewind($this->content);
  60.         return stream_get_contents($this->content);
  61.     }
  62.     public function toArray(bool $throw true): array
  63.     {
  64.         if ('' === $content $this->getContent($throw)) {
  65.             throw new JsonException('Response body is empty.');
  66.         }
  67.         if (null !== $this->jsonData) {
  68.             return $this->jsonData;
  69.         }
  70.         try {
  71.             $content json_decode($contenttrue512\JSON_BIGINT_AS_STRING \JSON_THROW_ON_ERROR);
  72.         } catch (\JsonException $e) {
  73.             throw new JsonException($e->getMessage().sprintf(' for "%s".'$this->getInfo('url')), $e->getCode());
  74.         }
  75.         if (!\is_array($content)) {
  76.             throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned for "%s".'get_debug_type($content), $this->getInfo('url')));
  77.         }
  78.         if (null !== $this->content) {
  79.             // Option "buffer" is true
  80.             return $this->jsonData $content;
  81.         }
  82.         return $content;
  83.     }
  84.     public function toStream(bool $throw true)
  85.     {
  86.         if ($throw) {
  87.             // Ensure headers arrived
  88.             $this->getHeaders($throw);
  89.         }
  90.         $stream StreamWrapper::createResource($this);
  91.         stream_get_meta_data($stream)['wrapper_data']
  92.             ->bindHandles($this->handle$this->content);
  93.         return $stream;
  94.     }
  95.     public function __sleep(): array
  96.     {
  97.         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  98.     }
  99.     public function __wakeup()
  100.     {
  101.         throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  102.     }
  103.     /**
  104.      * Closes the response and all its network handles.
  105.      */
  106.     abstract protected function close(): void;
  107.     private static function initialize(self $response): void
  108.     {
  109.         if (null !== $response->getInfo('error')) {
  110.             throw new TransportException($response->getInfo('error'));
  111.         }
  112.         try {
  113.             if (($response->initializer)($response, -0.0)) {
  114.                 foreach (self::stream([$response], -0.0) as $chunk) {
  115.                     if ($chunk->isFirst()) {
  116.                         break;
  117.                     }
  118.                 }
  119.             }
  120.         } catch (\Throwable $e) {
  121.             // Persist timeouts thrown during initialization
  122.             $response->info['error'] = $e->getMessage();
  123.             $response->close();
  124.             throw $e;
  125.         }
  126.         $response->initializer null;
  127.     }
  128.     private function checkStatusCode()
  129.     {
  130.         $code $this->getInfo('http_code');
  131.         if (500 <= $code) {
  132.             throw new ServerException($this);
  133.         }
  134.         if (400 <= $code) {
  135.             throw new ClientException($this);
  136.         }
  137.         if (300 <= $code) {
  138.             throw new RedirectionException($this);
  139.         }
  140.     }
  141. }