@@ -634,41 +634,102 @@ represented by a PHP callable instead of a string::
634634Streaming a JSON Response
635635~~~~~~~~~~~~~~~~~~~~~~~~~
636636
637- .. versionadded :: 6.2
637+ .. versionadded :: 6.3
638+
639+ The :class: `Symfony\\ Component\\ HttpFoundation\\ StreamedJsonResponse ` class was
640+ introduced in Symfony 6.3.
641+
642+ The :class: `Symfony\\ Component\\ HttpFoundation\\ StreamedJsonResponse ` allows an API to
643+ return a lot of data as JSON and keep the used resources low by make usage of Generators.
638644
639- The :class: `Symfony\\ Component\\ HttpFoundation\\ StreamedJsonResponse ` class allows
640- an API to return a lot of data as JSON and keep the used resources low by make usage
641- of Generators.
645+ It expects an array which represents the JSON structure and the list which should be
646+ streamed are represented in the array as ``\Generator ``. It also supports any kind of
647+ Traversable containing JSON Serializable data for a good developer experience,
648+ but for keep the resources usage low as possible it is recommended to use ``\Generators ``,
649+ as they the advantages that only the current returned data need to be keep in memory.
642650
643- It expects a JSON structure with one or multiple replacers identifiers, as example
644- the `'__articles__' `. As a second argument it requires one or multiple Generators
645- which items can be converted to a JSON via ``json_encode `` method. The key of the
646- Generators requires to be the used replacer identifiers::
651+ The response will stream the JSON with generators in to most efficient way and keep resources as low as possible::
647652
648653 use Symfony\Component\HttpFoundation\StreamedJsonResponse;
649654
655+ function loadArticles(): \Generator { // any method or function returning a Generator
656+ yield ['title' => 'Article 1'];
657+ yield ['title' => 'Article 2'];
658+ yield ['title' => 'Article 3'];
659+ };
660+
650661 $response = new StreamedJsonResponse(
651- // json structure with replace identifiers
662+ // json structure with generators in which will be streamed as a list
652663 [
653664 '_embedded' => [
654- 'articles' => '__articles__',
665+ 'articles' => loadArticles(), // any \Generator can be used which will be streamed as list of data
655666 ],
656667 ],
657- // array of generators with replace identifier used as key
658- [
659- '__articles__' => (function (): \Generator { // any method or function returning a Generator
660- yield ['title' => 'Article 1'];
661- yield ['title' => 'Article 2'];
662- yield ['title' => 'Article 3'];
663- })(),
664- ]
665668 );
666669
667670.. tip ::
668671
669672 If loading data via doctrine the ``toIterable `` method of ``Doctrine `` can be
670- used to keep also the resources low and fetch only one row one by one.
671- See the `Doctrine Batch processing `_ documentation for more.
673+ used to keep also the resources low and fetch only row by row.
674+ See the `Doctrine Batch processing `_ documentation for more::
675+
676+ public function __invoke(): Response
677+ {
678+ return new StreamedJsonResponse(
679+ [
680+ '_embedded' => [
681+ 'articles' => $this->loadArticles(),
682+ ],
683+ ],
684+ );
685+ }
686+
687+ public function loadArticles(): \Generator
688+ {
689+ $queryBuilder = $entityManager->createQueryBuilder();
690+ $queryBuilder->from(Article::class, 'article');
691+ $queryBuilder->select('article.id')
692+ ->addSelect('article.title')
693+ ->addSelect('article.description');
694+
695+ return $queryBuilder->getQuery()->toIterable();
696+ }
697+
698+ .. tip ::
699+
700+ If you have a lot of data to be returned you maybe want to call the
701+ PHP `flush <https://www.php.net/manual/en/function.flush.php >`__ method between
702+ to flush the response after every specific count of items::
703+
704+ public function __invoke(): Response
705+ {
706+ return new StreamedJsonResponse(
707+ [
708+ '_embedded' => [
709+ 'articles' => $this->loadArticles(),
710+ ],
711+ ],
712+ );
713+ }
714+
715+ public function loadArticles(): \Generator
716+ {
717+ $queryBuilder = $entityManager->createQueryBuilder();
718+ $queryBuilder->from(Article::class, 'article');
719+ $queryBuilder->select('article.id')
720+ ->addSelect('article.title')
721+ ->addSelect('article.description');
722+
723+ $count = 0;
724+ foreach ($queryBuilder->getQuery()->toIterable() as $article) {
725+ yield $article;
726+
727+ if (++$count % 100 === 0) {
728+ flush();
729+ }
730+ }
731+ }
732+
672733
673734Serving Files
674735~~~~~~~~~~~~~
0 commit comments