@@ -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('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
@@ -996,6 +1019,7 @@ First, to use ESI, be sure to enable it in your application configuration:
996
1019
http://symfony.com/schema/dic/services/services-1.0.xsd
997
1020
http://symfony.com/schema/dic/symfony
998
1021
http://symfony.com/schema/dic/symfony/symfony-1.0.xsd" >
1022
+ ">
999
1023
1000
1024
<framework : config >
1001
1025
<!-- ... -->
@@ -1017,13 +1041,19 @@ independent of the rest of the page.
1017
1041
1018
1042
.. code-block :: php
1019
1043
1020
- public function indexAction()
1044
+ // src/AppBundle/Controller/DefaultController.php
1045
+
1046
+ // ...
1047
+ class DefaultController extends Controller
1021
1048
{
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);
1049
+ public function aboutAction()
1050
+ {
1051
+ $response = $this->render('about.html.twig');
1052
+ // set the shared max age - which also marks the response as public
1053
+ $response->setSharedMaxAge(600);
1025
1054
1026
- return $response;
1055
+ return $response;
1056
+ }
1027
1057
}
1028
1058
1029
1059
In this example, the full-page cache has a lifetime of ten minutes.
@@ -1038,21 +1068,36 @@ matter), Symfony uses the standard ``render`` helper to configure ESI tags:
1038
1068
1039
1069
.. code-block :: jinja
1040
1070
1071
+ {# app/Resources/views/about.html.twig #}
1072
+
1041
1073
{# you can use a controller reference #}
1042
- {{ render_esi(controller('...:news ', { 'maxPerPage': 5 })) }}
1074
+ {{ render_esi(controller('AppBundle:News:latest ', { 'maxPerPage': 5 })) }}
1043
1075
1044
1076
{# ... or a URL #}
1045
1077
{{ render_esi(url('latest_news', { 'maxPerPage': 5 })) }}
1046
1078
1047
1079
.. code-block :: html+php
1048
1080
1081
+ <!-- app/Resources/views/about.html.php -->
1082
+
1083
+ // you can use a controller reference
1084
+ use Symfony\C omponent\H ttpKernel\C ontroller\C ontrollerReference;
1049
1085
<?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
- ?>
1086
+ new ControllerReference(
1087
+ 'AppBundle:News: latest',
1088
+ array('maxPerPage' => 5)
1089
+ ),
1090
+ array('strategy' => 'esi')
1091
+ ) ?>
1053
1092
1093
+ // ... or a URL
1094
+ use Symfony\C omponent\R outing\G enerator\U rlGeneratorInterface;
1054
1095
<?php echo $view['actions']->render(
1055
- $view['router']->generate('latest_news', array('maxPerPage' => 5), true),
1096
+ $view['router']->generate(
1097
+ 'latest_news',
1098
+ array('maxPerPage' => 5),
1099
+ UrlGeneratorInterface::ABSOLUTE_URL
1100
+ ),
1056
1101
array('strategy' => 'esi'),
1057
1102
) ?>
1058
1103
@@ -1072,7 +1117,7 @@ if there is no gateway cache installed.
1072
1117
When using the default ``render `` function (or setting the renderer to
1073
1118
``inline ``), Symfony merges the included page content into the main one
1074
1119
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
1120
+ (i.e. call ``render_esi ``) *and * if Symfony detects that it's talking to a
1076
1121
gateway cache that supports ESI, it generates an ESI include tag. But if there
1077
1122
is no gateway cache or if it does not support ESI, Symfony will just merge
1078
1123
the included page content within the main one as it would have done if you had
@@ -1089,11 +1134,19 @@ of the master page.
1089
1134
1090
1135
.. code-block :: php
1091
1136
1092
- public function newsAction($maxPerPage)
1137
+ // src/AppBundle/Controller/NewsController.php
1138
+ namespace AppBundle\Controller;
1139
+
1140
+ // ...
1141
+ class NewsController extends Controller
1093
1142
{
1094
- // ...
1143
+ public function latestAction($maxPerPage)
1144
+ {
1145
+ // ...
1146
+ $response->setSharedMaxAge(60);
1095
1147
1096
- $response->setSharedMaxAge(60);
1148
+ return $response;
1149
+ }
1097
1150
}
1098
1151
1099
1152
With ESI, the full page cache will be valid for 600 seconds, but the news
0 commit comments