@@ -634,41 +634,102 @@ represented by a PHP callable instead of a string::
634
634
Streaming a JSON Response
635
635
~~~~~~~~~~~~~~~~~~~~~~~~~
636
636
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.
638
644
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.
642
650
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::
647
652
648
653
use Symfony\Component\HttpFoundation\StreamedJsonResponse;
649
654
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
+
650
661
$response = new StreamedJsonResponse(
651
- // json structure with replace identifiers
662
+ // json structure with generators in which will be streamed as a list
652
663
[
653
664
'_embedded' => [
654
- 'articles' => '__articles__',
665
+ 'articles' => loadArticles(), // any \Generator can be used which will be streamed as list of data
655
666
],
656
667
],
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
- ]
665
668
);
666
669
667
670
.. tip ::
668
671
669
672
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
+
672
733
673
734
Serving Files
674
735
~~~~~~~~~~~~~
0 commit comments