@@ -629,8 +629,6 @@ represented by a PHP callable instead of a string::
629
629
// disables FastCGI buffering in nginx only for this response
630
630
$response->headers->set('X-Accel-Buffering', 'no');
631
631
632
- .. _component-http-foundation-serving-files :
633
-
634
632
Streaming a JSON Response
635
633
~~~~~~~~~~~~~~~~~~~~~~~~~
636
634
@@ -639,94 +637,79 @@ Streaming a JSON Response
639
637
The :class: `Symfony\\ Component\\ HttpFoundation\\ StreamedJsonResponse ` class was
640
638
introduced in Symfony 6.3.
641
639
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 .
640
+ The :class: `Symfony\\ Component\\ HttpFoundation\\ StreamedJsonResponse ` allows to
641
+ stream large JSON responses using PHP generators to keep the used resources low.
644
642
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 as 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.
650
-
651
- The response will stream the JSON with generators in to most efficient way and keep resources as low as possible::
643
+ The class constructor expects an array which represents the JSON structure and
644
+ includes the list of contents to stream. In addition to PHP generators, which are
645
+ recommended to minimize memory usage, it also supports any kind of PHP Traversable
646
+ containing JSON serializable data::
652
647
653
648
use Symfony\Component\HttpFoundation\StreamedJsonResponse;
654
649
655
- function loadArticles(): \Generator { // any method or function returning a Generator
650
+ // any method or function returning a PHP Generator
651
+ function loadArticles(): \Generator {
656
652
yield ['title' => 'Article 1'];
657
653
yield ['title' => 'Article 2'];
658
654
yield ['title' => 'Article 3'];
659
655
};
660
656
661
657
$response = new StreamedJsonResponse(
662
- // json structure with generators in which will be streamed as a list
658
+ // JSON structure with generators in which will be streamed as a list
663
659
[
664
660
'_embedded' => [
665
- 'articles' => loadArticles(), // any \Generator can be used which will be streamed as list of data
661
+ 'articles' => loadArticles(),
666
662
],
667
663
],
668
664
);
669
665
670
- .. tip ::
671
-
672
- If loading data via doctrine the ``toIterable `` method of ``Doctrine `` can be
673
- used to keep the resources low and fetch only row by row.
674
- See the `Doctrine Batch processing `_ documentation for more::
666
+ When loading data via Doctrine, you can use the ``toIterable() `` method to
667
+ fetch results row by row and minimize resources consumption.
668
+ See the `Doctrine Batch processing `_ documentation for more::
675
669
676
- public function __invoke(): Response
677
- {
678
- return new StreamedJsonResponse(
679
- [
680
- '_embedded' => [
681
- 'articles' => $this->loadArticles(),
682
- ],
670
+ public function __invoke(): Response
671
+ {
672
+ return new StreamedJsonResponse(
673
+ [
674
+ '_embedded' => [
675
+ 'articles' => $this->loadArticles(),
683
676
],
684
- );
685
- }
677
+ ],
678
+ );
679
+ }
686
680
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');
681
+ public function loadArticles(): \Generator
682
+ {
683
+ // get the $entityManager somehow (e.g. via constructor injection)
684
+ $entityManager = ...
694
685
695
- return $queryBuilder->getQuery()->toIterable();
696
- }
686
+ $queryBuilder = $entityManager->createQueryBuilder();
687
+ $queryBuilder->from(Article::class, 'article');
688
+ $queryBuilder->select('article.id')
689
+ ->addSelect('article.title')
690
+ ->addSelect('article.description');
697
691
698
- .. tip ::
692
+ return $queryBuilder->getQuery()->toIterable();
693
+ }
699
694
700
- If you have a lot of data to be returned you may 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::
695
+ If you return a lot of data, consider calling the :phpfunction: `flush ` function
696
+ after some specific item count to send the contents to the browser::
703
697
704
- public function __invoke(): Response
705
- {
706
- return new StreamedJsonResponse([
707
- '_embedded' => [
708
- 'articles' => $this->loadArticles(),
709
- ],
710
- ]);
711
- }
698
+ public function loadArticles(): \Generator
699
+ {
700
+ // ...
712
701
713
- public function loadArticles(): \Generator
714
- {
715
- $queryBuilder = $entityManager->createQueryBuilder();
716
- $queryBuilder->from(Article::class, 'article');
717
- $queryBuilder->select('article.id')
718
- ->addSelect('article.title')
719
- ->addSelect('article.description');
720
-
721
- $count = 0;
722
- foreach ($queryBuilder->getQuery()->toIterable() as $article) {
723
- yield $article;
724
-
725
- if (++$count % 100 === 0) {
726
- flush();
727
- }
702
+ $count = 0;
703
+ foreach ($queryBuilder->getQuery()->toIterable() as $article) {
704
+ yield $article;
705
+
706
+ if (0 === ++$count % 100) {
707
+ flush();
728
708
}
729
709
}
710
+ }
711
+
712
+ .. _component-http-foundation-serving-files :
730
713
731
714
Serving Files
732
715
~~~~~~~~~~~~~
0 commit comments