Back | Home
الـ Path الحالي: /home/picotech/domains/instantly.picotech.app/public_html/public/../lang/../vendor/symfony/finder/../mailchimp-mailer/.././http-foundation
الملفات الموجودة في هذا الـ Path:
.
..
AcceptHeader.php
AcceptHeaderItem.php
BinaryFileResponse.php
CHANGELOG.md
ChainRequestMatcher.php
Cookie.php
Exception
ExpressionRequestMatcher.php
File
FileBag.php
HeaderBag.php
HeaderUtils.php
InputBag.php
IpUtils.php
JsonResponse.php
LICENSE
ParameterBag.php
README.md
RateLimiter
RedirectResponse.php
Request.php
RequestMatcher
RequestMatcher.php
RequestMatcherInterface.php
RequestStack.php
Response.php
ResponseHeaderBag.php
ServerBag.php
Session
StreamedJsonResponse.php
StreamedResponse.php
Test
UrlHelper.php
composer.json

مشاهدة ملف: StreamedJsonResponse.php

<?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\HttpFoundation;

/**
 * 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.
 *
 * @see flush()
 *
 * @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
 *             ],
 *         ],
 *     );
 */
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
     * @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(
        private readonly array $data,
        int $status = 200,
        array $headers = [],
        private 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
    {
        $generators = [];
        $structure = $this->data;

        array_walk_recursive($structure, 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;
            }
        });

        $jsonEncodingOptions = \JSON_THROW_ON_ERROR | $this->encodingOptions;
        $keyEncodingOptions = $jsonEncodingOptions & ~\JSON_NUMERIC_CHECK;

        $jsonParts = explode('"'.self::PLACEHOLDER.'"', json_encode($structure, $jsonEncodingOptions));

        foreach ($generators as $index => $generator) {
            // send first and between parts of the structure
            echo $jsonParts[$index];

            if ($generator instanceof \JsonSerializable || !$generator instanceof \Traversable) {
                // the placeholders, JsonSerializable and none traversable items in the structure are rendered here
                echo json_encode($generator, $jsonEncodingOptions);

                continue;
            }

            $isFirstItem = true;
            $startTag = '[';

            foreach ($generator 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).':';
                }

                echo json_encode($item, $jsonEncodingOptions);
            }

            if ($isFirstItem) { // indicates that the generator was empty
                echo '[';
            }

            echo '[' === $startTag ? ']' : '}';
        }

        // send last part of the structure
        echo $jsonParts[array_key_last($jsonParts)];
    }
}