@@ -155,9 +155,12 @@ kernel::
155
155
$kernel->loadClassCache();
156
156
// wrap the default AppKernel with the AppCache one
157
157
$kernel = new AppCache($kernel);
158
+
158
159
$request = Request::createFromGlobals();
160
+
159
161
$response = $kernel->handle($request);
160
162
$response->send();
163
+
161
164
$kernel->terminate($request, $response);
162
165
163
166
The caching kernel will immediately act as a reverse proxy - caching responses
@@ -576,16 +579,22 @@ each ``ETag`` must be unique across all representations of the same resource.
576
579
577
580
To see a simple implementation, generate the ETag as the md5 of the content::
578
581
582
+ // src/AppBundle/Controller/DefaultController.php
583
+ namespace AppBundle\Controller;
584
+
579
585
use Symfony\Component\HttpFoundation\Request;
580
586
581
- public function indexAction(Request $request)
587
+ class DefaultController extends Controller
582
588
{
583
- $response = $this->render('MyBundle:Main:index.html.twig');
584
- $response->setETag(md5($response->getContent()));
585
- $response->setPublic(); // make sure the response is public/cacheable
586
- $response->isNotModified($request);
589
+ public function homepageAction(Request $request)
590
+ {
591
+ $response = $this->render('static/homepage.html.twig');
592
+ $response->setETag(md5($response->getContent()));
593
+ $response->setPublic(); // make sure the response is public/cacheable
594
+ $response->isNotModified($request);
587
595
588
- return $response;
596
+ return $response;
597
+ }
589
598
}
590
599
591
600
The :method: `Symfony\\ Component\\ HttpFoundation\\ Response::isNotModified `
@@ -632,28 +641,36 @@ For instance, you can use the latest update date for all the objects needed to
632
641
compute the resource representation as the value for the ``Last-Modified ``
633
642
header value::
634
643
644
+ // src/AppBundle/Controller/ArticleController.php
645
+ namespace AppBundle\Controller;
646
+
647
+ // ...
635
648
use Symfony\Component\HttpFoundation\Request;
649
+ use AppBundle\Entity\Article;
636
650
637
- public function showAction($articleSlug, Request $request)
651
+ class ArticleController extends Controller
638
652
{
639
- // ...
653
+ public function showAction(Article $article, Request $request)
654
+ {
655
+ $author = $article->getAuthor();
640
656
641
- $articleDate = new \DateTime($article->getUpdatedAt());
642
- $authorDate = new \DateTime($author->getUpdatedAt());
657
+ $articleDate = new \DateTime($article->getUpdatedAt());
658
+ $authorDate = new \DateTime($author->getUpdatedAt());
643
659
644
- $date = $authorDate > $articleDate ? $authorDate : $articleDate;
660
+ $date = $authorDate > $articleDate ? $authorDate : $articleDate;
645
661
646
- $response->setLastModified($date);
647
- // Set response as public. Otherwise it will be private by default.
648
- $response->setPublic();
662
+ $response->setLastModified($date);
663
+ // Set response as public. Otherwise it will be private by default.
664
+ $response->setPublic();
649
665
650
- if ($response->isNotModified($request)) {
651
- return $response;
652
- }
666
+ if ($response->isNotModified($request)) {
667
+ return $response;
668
+ }
653
669
654
- // ... do more work to populate the response with the full content
670
+ // ... do more work to populate the response with the full content
655
671
656
- return $response;
672
+ return $response;
673
+ }
657
674
}
658
675
659
676
The :method: `Symfony\\ Component\\ HttpFoundation\\ Response::isNotModified `
@@ -682,40 +699,46 @@ Put another way, the less you do in your application to return a 304 response,
682
699
the better. The ``Response::isNotModified() `` method does exactly that by
683
700
exposing a simple and efficient pattern::
684
701
702
+ // src/AppBundle/Controller/ArticleController.php
703
+ namespace AppBundle\Controller;
704
+
705
+ // ...
685
706
use Symfony\Component\HttpFoundation\Response;
686
707
use Symfony\Component\HttpFoundation\Request;
687
708
688
- public function showAction($articleSlug, Request $request)
709
+ class ArticleController extends Controller
689
710
{
690
- // Get the minimum information to compute
691
- // the ETag or the Last-Modified value
692
- // (based on the Request, data is retrieved from
693
- // a database or a key-value store for instance)
694
- $article = ...;
695
-
696
- // create a Response with an ETag and/or a Last-Modified header
697
- $response = new Response();
698
- $response->setETag($article->computeETag());
699
- $response->setLastModified($article->getPublishedAt());
700
-
701
- // Set response as public. Otherwise it will be private by default.
702
- $response->setPublic();
703
-
704
- // Check that the Response is not modified for the given Request
705
- if ($response->isNotModified($request)) {
706
- // return the 304 Response immediately
707
- return $response;
708
- }
711
+ public function showAction($articleSlug, Request $request)
712
+ {
713
+ // Get the minimum information to compute
714
+ // the ETag or the Last-Modified value
715
+ // (based on the Request, data is retrieved from
716
+ // a database or a key-value store for instance)
717
+ $article = ...;
718
+
719
+ // create a Response with an ETag and/or a Last-Modified header
720
+ $response = new Response();
721
+ $response->setETag($article->computeETag());
722
+ $response->setLastModified($article->getPublishedAt());
723
+
724
+ // Set response as public. Otherwise it will be private by default.
725
+ $response->setPublic();
726
+
727
+ // Check that the Response is not modified for the given Request
728
+ if ($response->isNotModified($request)) {
729
+ // return the 304 Response immediately
730
+ return $response;
731
+ }
709
732
710
- // do more work here - like retrieving more data
711
- $comments = ...;
733
+ // do more work here - like retrieving more data
734
+ $comments = ...;
712
735
713
- // or render a template with the $response you've already started
714
- return $this->render(
715
- 'MyBundle:MyController: article.html.twig' ,
716
- array('article' => $article, 'comments' => $comments),
717
- $response
718
- );
736
+ // or render a template with the $response you've already started
737
+ return $this->render('Article/show.html.twig', array (
738
+ ' article' => $article ,
739
+ 'comments' => $comments
740
+ ), $response);
741
+ }
719
742
}
720
743
721
744
When the ``Response `` is not modified, the ``isNotModified() `` automatically sets
@@ -865,10 +888,10 @@ Here is how you can configure the Symfony reverse proxy to support the
865
888
866
889
// app/AppCache.php
867
890
868
- // ...
869
891
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
870
892
use Symfony\Component\HttpFoundation\Request;
871
893
use Symfony\Component\HttpFoundation\Response;
894
+ // ...
872
895
873
896
class AppCache extends HttpCache
874
897
{
@@ -930,7 +953,7 @@ have one limitation: they can only cache whole pages. If you can't cache
930
953
whole pages or if parts of a page has "more" dynamic parts, you are out of
931
954
luck. Fortunately, Symfony provides a solution for these cases, based on a
932
955
technology called `ESI `_, or Edge Side Includes. Akamai wrote this specification
933
- almost 10 years ago, and it allows specific parts of a page to have a different
956
+ almost 10 years ago and it allows specific parts of a page to have a different
934
957
caching strategy than the main page.
935
958
936
959
The ESI specification describes tags you can embed in your pages to communicate
@@ -1017,13 +1040,19 @@ independent of the rest of the page.
1017
1040
1018
1041
.. code-block :: php
1019
1042
1020
- public function indexAction()
1043
+ // src/AppBundle/Controller/DefaultController.php
1044
+
1045
+ // ...
1046
+ class DefaultController extends Controller
1021
1047
{
1022
- $response = $this->render('MyBundle:MyController:index.html.twig');
1023
- // set the shared max age - which also marks the response as public
1024
- $response->setSharedMaxAge(600);
1048
+ public function aboutAction()
1049
+ {
1050
+ $response = $this->render('static/about.html.twig');
1051
+ // set the shared max age - which also marks the response as public
1052
+ $response->setSharedMaxAge(600);
1025
1053
1026
- return $response;
1054
+ return $response;
1055
+ }
1027
1056
}
1028
1057
1029
1058
In this example, the full-page cache has a lifetime of ten minutes.
@@ -1038,21 +1067,36 @@ matter), Symfony uses the standard ``render`` helper to configure ESI tags:
1038
1067
1039
1068
.. code-block :: jinja
1040
1069
1070
+ {# app/Resources/views/static/about.html.twig #}
1071
+
1041
1072
{# you can use a controller reference #}
1042
- {{ render_esi(controller('...:news ', { 'maxPerPage': 5 })) }}
1073
+ {{ render_esi(controller('AppBundle:News:latest ', { 'maxPerPage': 5 })) }}
1043
1074
1044
1075
{# ... or a URL #}
1045
1076
{{ render_esi(url('latest_news', { 'maxPerPage': 5 })) }}
1046
1077
1047
1078
.. code-block :: html+php
1048
1079
1080
+ <!-- app/Resources/views/static/about.html.php -->
1081
+
1082
+ // you can use a controller reference
1083
+ use Symfony\C omponent\H ttpKernel\C ontroller\C ontrollerReference;
1049
1084
<?php echo $view['actions']->render(
1050
- new \S ymfony\C omponent\H ttpKernel\C ontroller\C ontrollerReference('...:news', array('maxPerPage' => 5)),
1051
- array('strategy' => 'esi'))
1052
- ?>
1085
+ new ControllerReference(
1086
+ 'AppBundle:News: latest',
1087
+ array('maxPerPage' => 5)
1088
+ ),
1089
+ array('strategy' => 'esi')
1090
+ ) ?>
1053
1091
1092
+ // ... or a URL
1093
+ use Symfony\C omponent\R outing\G enerator\U rlGeneratorInterface;
1054
1094
<?php echo $view['actions']->render(
1055
- $view['router']->generate('latest_news', array('maxPerPage' => 5), true),
1095
+ $view['router']->generate(
1096
+ 'latest_news',
1097
+ array('maxPerPage' => 5),
1098
+ UrlGeneratorInterface::ABSOLUTE_URL
1099
+ ),
1056
1100
array('strategy' => 'esi'),
1057
1101
) ?>
1058
1102
@@ -1072,7 +1116,7 @@ if there is no gateway cache installed.
1072
1116
When using the default ``render `` function (or setting the renderer to
1073
1117
``inline ``), Symfony merges the included page content into the main one
1074
1118
before sending the response to the client. But if you use the ``esi `` renderer
1075
- (i.e. call ``render_esi ``), *and * if Symfony detects that it's talking to a
1119
+ (i.e. call ``render_esi ``) *and * if Symfony detects that it's talking to a
1076
1120
gateway cache that supports ESI, it generates an ESI include tag. But if there
1077
1121
is no gateway cache or if it does not support ESI, Symfony will just merge
1078
1122
the included page content within the main one as it would have done if you had
@@ -1089,11 +1133,19 @@ of the master page.
1089
1133
1090
1134
.. code-block :: php
1091
1135
1092
- public function newsAction($maxPerPage)
1136
+ // src/AppBundle/Controller/NewsController.php
1137
+ namespace AppBundle\Controller;
1138
+
1139
+ // ...
1140
+ class NewsController extends Controller
1093
1141
{
1094
- // ...
1142
+ public function latestAction($maxPerPage)
1143
+ {
1144
+ // ...
1145
+ $response->setSharedMaxAge(60);
1095
1146
1096
- $response->setSharedMaxAge(60);
1147
+ return $response;
1148
+ }
1097
1149
}
1098
1150
1099
1151
With ESI, the full page cache will be valid for 600 seconds, but the news
0 commit comments