Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. StreamedJsonResponse.php

class StreamedJsonResponse

StreamedJsonResponse represents a streamed HTTP response for JSON.

A StreamedJsonResponse uses a structure and generics to create an efficient resource-saving JSON response.

It is recommended to use flush() function after a specific number of items to directly stream the data.

@author Alexander Schranz <alexander@sulu.io>

Example usage:

function loadArticles(): \Generator // some streamed loading yield ['title' => 'Article 1']; yield ['title' => 'Article 2']; yield ['title' => 'Article 3']; // recommended to use flush() after every specific number of items }),

$response = new StreamedJsonResponse( // json structure with generators in which will be streamed [ '_embedded' => [ 'articles' => loadArticles(), // any generator which you want to stream as list of data ], ], );

Hierarchy

  • class \Symfony\Component\HttpFoundation\Response
    • class \Symfony\Component\HttpFoundation\StreamedResponse extends \Symfony\Component\HttpFoundation\Response
      • class \Symfony\Component\HttpFoundation\StreamedJsonResponse extends \Symfony\Component\HttpFoundation\StreamedResponse

Expanded class hierarchy of StreamedJsonResponse

See also

flush()

File

vendor/symfony/http-foundation/StreamedJsonResponse.php, line 45

Namespace

Symfony\Component\HttpFoundation
View source
class StreamedJsonResponse extends StreamedResponse {
    private const PLACEHOLDER = '__symfony_json__';
    
    /**
     * @param mixed[]                        $data            JSON Data containing PHP generators which will be streamed as list of data or a Generator
     * @param int                            $status          The HTTP status code (200 "OK" by default)
     * @param array<string, string|string[]> $headers         An array of HTTP headers
     * @param int                            $encodingOptions Flags for the json_encode() function
     */
    public function __construct(iterable $data, int $status = 200, array $headers = [], int $encodingOptions = JsonResponse::DEFAULT_ENCODING_OPTIONS) {
        parent::__construct($this->stream(...), $status, $headers);
        if (!$this->headers
            ->get('Content-Type')) {
            $this->headers
                ->set('Content-Type', 'application/json');
        }
    }
    private function stream() : void {
        $jsonEncodingOptions = \JSON_THROW_ON_ERROR | $this->encodingOptions;
        $keyEncodingOptions = $jsonEncodingOptions & ~\JSON_NUMERIC_CHECK;
        $this->streamData($this->data, $jsonEncodingOptions, $keyEncodingOptions);
    }
    private function streamData(mixed $data, int $jsonEncodingOptions, int $keyEncodingOptions) : void {
        if (\is_array($data)) {
            $this->streamArray($data, $jsonEncodingOptions, $keyEncodingOptions);
            return;
        }
        if (is_iterable($data) && !$data instanceof \JsonSerializable) {
            $this->streamIterable($data, $jsonEncodingOptions, $keyEncodingOptions);
            return;
        }
        echo json_encode($data, $jsonEncodingOptions);
    }
    private function streamArray(array $data, int $jsonEncodingOptions, int $keyEncodingOptions) : void {
        $generators = [];
        array_walk_recursive($data, function (&$item, $key) use (&$generators) {
            if (self::PLACEHOLDER === $key) {
                // if the placeholder is already in the structure it should be replaced with a new one that explode
                // works like expected for the structure
                $generators[] = $key;
            }
            // generators should be used but for better DX all kind of Traversable and objects are supported
            if (\is_object($item)) {
                $generators[] = $item;
                $item = self::PLACEHOLDER;
            }
            elseif (self::PLACEHOLDER === $item) {
                // if the placeholder is already in the structure it should be replaced with a new one that explode
                // works like expected for the structure
                $generators[] = $item;
            }
        });
        $jsonParts = explode('"' . self::PLACEHOLDER . '"', json_encode($data, $jsonEncodingOptions));
        foreach ($generators as $index => $generator) {
            // send first and between parts of the structure
            echo $jsonParts[$index];
            $this->streamData($generator, $jsonEncodingOptions, $keyEncodingOptions);
        }
        // send last part of the structure
        echo $jsonParts[array_key_last($jsonParts)];
    }
    private function streamIterable(iterable $iterable, int $jsonEncodingOptions, int $keyEncodingOptions) : void {
        $isFirstItem = true;
        $startTag = '[';
        foreach ($iterable as $key => $item) {
            if ($isFirstItem) {
                $isFirstItem = false;
                // depending on the first elements key the generator is detected as a list or map
                // we can not check for a whole list or map because that would hurt the performance
                // of the streamed response which is the main goal of this response class
                if (0 !== $key) {
                    $startTag = '{';
                }
                echo $startTag;
            }
            else {
                // if not first element of the generic, a separator is required between the elements
                echo ',';
            }
            if ('{' === $startTag) {
                echo json_encode((string) $key, $keyEncodingOptions) . ':';
            }
            $this->streamData($item, $jsonEncodingOptions, $keyEncodingOptions);
        }
        if ($isFirstItem) {
            // indicates that the generator was empty
            echo '[';
        }
        echo '[' === $startTag ? ']' : '}';
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
Response::$charset protected property
Response::$content protected property
Response::$headers public property
Response::$sentHeaders private property Tracks headers already sent in informational responses.
Response::$statusCode protected property
Response::$statusText protected property
Response::$statusTexts public static property Status codes translation table.
Response::$version protected property
Response::closeOutputBuffers public static function Cleans or flushes output buffers up to target level.
Response::ensureIEOverSSLCompatibility protected function Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE &lt; 9.
Response::expire public function Marks the response stale by setting the Age header to be equal to the maximum age of the response.
Response::getAge public function Returns the age of the response in seconds.
Response::getCharset public function Retrieves the response charset.
Response::getDate public function Returns the Date header as a DateTime instance.
Response::getEtag public function Returns the literal value of the ETag HTTP header.
Response::getExpires public function Returns the value of the Expires header as a DateTime instance.
Response::getLastModified public function Returns the Last-Modified HTTP header as a DateTime instance.
Response::getMaxAge public function Returns the number of seconds after the time specified in the response&#039;s Date
header when the response should no longer be considered fresh.
Response::getProtocolVersion public function Gets the HTTP protocol version.
Response::getStatusCode public function Retrieves the status code for the current web response.
Response::getTtl public function Returns the response&#039;s time-to-live in seconds.
Response::getVary public function Returns an array of header names given in the Vary header.
Response::hasVary public function Returns true if the response includes a Vary header.
Response::HTTP_ACCEPTED public constant
Response::HTTP_ALREADY_REPORTED public constant
Response::HTTP_BAD_GATEWAY public constant
Response::HTTP_BAD_REQUEST public constant
Response::HTTP_CONFLICT public constant
Response::HTTP_CONTINUE public constant
Response::HTTP_CREATED public constant
Response::HTTP_EARLY_HINTS public constant
Response::HTTP_EXPECTATION_FAILED public constant
Response::HTTP_FAILED_DEPENDENCY public constant
Response::HTTP_FORBIDDEN public constant
Response::HTTP_FOUND public constant
Response::HTTP_GATEWAY_TIMEOUT public constant
Response::HTTP_GONE public constant
Response::HTTP_IM_USED public constant
Response::HTTP_INSUFFICIENT_STORAGE public constant
Response::HTTP_INTERNAL_SERVER_ERROR public constant
Response::HTTP_I_AM_A_TEAPOT public constant
Response::HTTP_LENGTH_REQUIRED public constant
Response::HTTP_LOCKED public constant
Response::HTTP_LOOP_DETECTED public constant
Response::HTTP_METHOD_NOT_ALLOWED public constant
Response::HTTP_MISDIRECTED_REQUEST public constant
Response::HTTP_MOVED_PERMANENTLY public constant
Response::HTTP_MULTIPLE_CHOICES public constant
Response::HTTP_MULTI_STATUS public constant
Response::HTTP_NETWORK_AUTHENTICATION_REQUIRED public constant
Response::HTTP_NON_AUTHORITATIVE_INFORMATION public constant
Response::HTTP_NOT_ACCEPTABLE public constant
Response::HTTP_NOT_EXTENDED public constant
Response::HTTP_NOT_FOUND public constant
Response::HTTP_NOT_IMPLEMENTED public constant
Response::HTTP_NOT_MODIFIED public constant
Response::HTTP_NO_CONTENT public constant
Response::HTTP_OK public constant
Response::HTTP_PARTIAL_CONTENT public constant
Response::HTTP_PAYMENT_REQUIRED public constant
Response::HTTP_PERMANENTLY_REDIRECT public constant
Response::HTTP_PRECONDITION_FAILED public constant
Response::HTTP_PRECONDITION_REQUIRED public constant
Response::HTTP_PROCESSING public constant
Response::HTTP_PROXY_AUTHENTICATION_REQUIRED public constant
Response::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE public constant
Response::HTTP_REQUEST_ENTITY_TOO_LARGE public constant
Response::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE public constant
Response::HTTP_REQUEST_TIMEOUT public constant
Response::HTTP_REQUEST_URI_TOO_LONG public constant
Response::HTTP_RESERVED public constant
Response::HTTP_RESET_CONTENT public constant
Response::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES private constant
Response::HTTP_SEE_OTHER public constant
Response::HTTP_SERVICE_UNAVAILABLE public constant
Response::HTTP_SWITCHING_PROTOCOLS public constant
Response::HTTP_TEMPORARY_REDIRECT public constant
Response::HTTP_TOO_EARLY public constant
Response::HTTP_TOO_MANY_REQUESTS public constant
Response::HTTP_UNAUTHORIZED public constant
Response::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS public constant
Response::HTTP_UNPROCESSABLE_ENTITY public constant
Response::HTTP_UNSUPPORTED_MEDIA_TYPE public constant
Response::HTTP_UPGRADE_REQUIRED public constant
Response::HTTP_USE_PROXY public constant
Response::HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL public constant
Response::HTTP_VERSION_NOT_SUPPORTED public constant
Response::isCacheable public function Returns true if the response may safely be kept in a shared (surrogate) cache.
Response::isClientError public function Is there a client error?
Response::isEmpty public function Is the response empty?
Response::isForbidden public function Is the response forbidden?
Response::isFresh public function Returns true if the response is &quot;fresh&quot;.
Response::isImmutable public function Returns true if the response is marked as &quot;immutable&quot;.
Response::isInformational public function Is response informative?
Response::isInvalid public function Is response invalid?
Response::isNotFound public function Is the response a not found error?
Response::isNotModified public function Determines if the Response validators (ETag, Last-Modified) match
a conditional value specified in the Request.
Response::isOk public function Is the response OK?
Response::isRedirect public function Is the response a redirect of some form?
Response::isRedirection public function Is the response a redirect?
Response::isServerError public function Was there a server side error?
Response::isSuccessful public function Is response successful?
Response::isValidateable public function Returns true if the response includes headers that can be used to validate
the response with the origin server using a conditional GET request.
Response::mustRevalidate public function Returns true if the response must be revalidated by shared caches once it has become stale.
Response::prepare public function Prepares the Response before it is sent to the client. 1
Response::send public function Sends HTTP headers and content.
Response::setCache public function Sets the response&#039;s cache headers (validation and/or expiration).
Response::setCharset public function Sets the response charset.
Response::setClientTtl public function Sets the response&#039;s time-to-live for private/client caches in seconds.
Response::setContentSafe public function Marks a response as safe according to RFC8674.
Response::setDate public function Sets the Date header.
Response::setEtag public function Sets the ETag value.
Response::setExpires public function Sets the Expires HTTP header with a DateTime instance.
Response::setImmutable public function Marks the response as &quot;immutable&quot;.
Response::setLastModified public function Sets the Last-Modified HTTP header with a DateTime instance.
Response::setMaxAge public function Sets the number of seconds after which the response should no longer be considered fresh.
Response::setNotModified public function Modifies the response so that it conforms to the rules defined for a 304 status code.
Response::setPrivate public function Marks the response as &quot;private&quot;.
Response::setProtocolVersion public function Sets the HTTP protocol version (1.0 or 1.1).
Response::setPublic public function Marks the response as &quot;public&quot;.
Response::setSharedMaxAge public function Sets the number of seconds after which the response should no longer be considered fresh by shared caches.
Response::setStaleIfError public function Sets the number of seconds after which the response should no longer be returned by shared caches when backend is down.
Response::setStaleWhileRevalidate public function Sets the number of seconds after which the response should no longer return stale content by shared caches.
Response::setStatusCode public function Sets the response status code.
Response::setTtl public function Sets the response&#039;s time-to-live for shared caches in seconds.
Response::setVary public function Sets the Vary header.
Response::__clone public function Clones the current Response instance.
Response::__toString public function Returns the Response as an HTTP string.
StreamedJsonResponse::PLACEHOLDER private constant
StreamedJsonResponse::stream private function
StreamedJsonResponse::streamArray private function
StreamedJsonResponse::streamData private function
StreamedJsonResponse::streamIterable private function
StreamedJsonResponse::__construct public function Overrides StreamedResponse::__construct
StreamedResponse::$callback protected property
StreamedResponse::$headersSent private property
StreamedResponse::$streamed protected property
StreamedResponse::getCallback public function
StreamedResponse::getContent public function Gets the current response content. Overrides Response::getContent
StreamedResponse::sendContent public function This method only sends the content once. Overrides Response::sendContent
StreamedResponse::sendHeaders public function This method only sends the headers once. Overrides Response::sendHeaders
StreamedResponse::setCallback public function Sets the PHP callback associated with this Response.
StreamedResponse::setContent public function Overrides Response::setContent

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal