Permalink
Browse files

feature #10702 [HttpKernel][FrameworkBundle] SSI support (KingCrunch)

This PR was merged into the 2.6-dev branch.

Discussion
----------

[HttpKernel][FrameworkBundle] SSI support

| Q             | A
| ------------- | ---
| Bug fix?      | No
| New feature?  | Yes
| BC breaks?    | No
| Deprecations? | No
| Tests pass?   | Yes
| Fixed tickets | #9419 (, #10684)
| License       | MIT

It does not support comments, or alternative URIs, or "continue" in case of errors. Maybe I can workaround that, but I've decided to left it out for this PR. Especially as far as I can see a "alternative URIs"-hack would _always_ lead to two requests, even if it's not needed.

Commits
-------

06cea08 SSI support
  • Loading branch information...
fabpot committed Jul 25, 2014
2 parents fb9dc6a + 06cea08 commit bf140a8487a19d767b9b57102e74c842e8f0a208
Showing with 1,019 additions and 207 deletions.
  1. +12 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
  2. +17 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
  3. +14 −2 src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php
  4. +13 −0 src/Symfony/Bundle/FrameworkBundle/Resources/config/fragment_renderer.xml
  5. +20 −0 src/Symfony/Bundle/FrameworkBundle/Resources/config/ssi.xml
  6. +1 −0 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
  7. +3 −38 src/Symfony/Component/HttpKernel/EventListener/EsiListener.php
  8. +58 −0 src/Symfony/Component/HttpKernel/EventListener/SurrogateListener.php
  9. +79 −0 src/Symfony/Component/HttpKernel/Fragment/AbstractSurrogateFragmentRenderer.php
  10. +1 −57 src/Symfony/Component/HttpKernel/Fragment/EsiFragmentRenderer.php
  11. +59 −0 src/Symfony/Component/HttpKernel/Fragment/SsiFragmentRenderer.php
  12. +48 −3 src/Symfony/Component/HttpKernel/HttpCache/Esi.php
  13. +3 −57 src/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategy.php
  14. +5 −18 src/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategyInterface.php
  15. +37 −18 src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
  16. +85 −0 src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
  17. +41 −0 src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategyInterface.php
  18. +197 −0 src/Symfony/Component/HttpKernel/HttpCache/Ssi.php
  19. +103 −0 src/Symfony/Component/HttpKernel/HttpCache/SurrogateInterface.php
  20. +4 −4 src/Symfony/Component/HttpKernel/Tests/EventListener/EsiListenerTest.php
  21. +10 −10 src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php
  22. +209 −0 src/Symfony/Component/HttpKernel/Tests/HttpCache/SsiTest.php
@@ -81,6 +81,7 @@ public function getConfigTreeBuilder()
$this->addCsrfSection($rootNode);
$this->addFormSection($rootNode);
$this->addEsiSection($rootNode);
$this->addSsiSection($rootNode);
$this->addFragmentsSection($rootNode);
$this->addProfilerSection($rootNode);
$this->addRouterSection($rootNode);
@@ -148,6 +149,17 @@ private function addEsiSection(ArrayNodeDefinition $rootNode)
;
}
private function addSsiSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('ssi')
->info('ssi configuration')
->canBeEnabled()
->end()
->end();
}
private function addFragmentsSection(ArrayNodeDefinition $rootNode)
{
$rootNode
@@ -122,6 +122,7 @@ public function load(array $configs, ContainerBuilder $container)
$this->registerValidationConfiguration($config['validation'], $container, $loader);
$this->registerEsiConfiguration($config['esi'], $container, $loader);
$this->registerSsiConfiguration($config['ssi'], $container, $loader);
$this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
$this->registerProfilerConfiguration($config['profiler'], $container, $loader);
$this->registerTranslatorConfiguration($config['translator'], $container);
@@ -208,6 +209,22 @@ private function registerEsiConfiguration(array $config, ContainerBuilder $conta
$loader->load('esi.xml');
}
/**
* Loads the SSI configuration.
*
* @param array $config An SSI configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
* @param XmlFileLoader $loader An XmlFileLoader instance
*/
private function registerSsiConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
if (!$this->isConfigEnabled($container, $config)) {
return;
}
$loader->load('ssi.xml');
}
/**
* Loads the fragments configuration.
*
@@ -39,7 +39,7 @@ public function __construct(HttpKernelInterface $kernel, $cacheDir = null)
$this->kernel = $kernel;
$this->cacheDir = $cacheDir;
parent::__construct($kernel, $this->createStore(), $this->createEsi(), array_merge(array('debug' => $kernel->isDebug()), $this->getOptions()));
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge(array('debug' => $kernel->isDebug()), $this->getOptions()));
}
/**
@@ -55,7 +55,7 @@ protected function forward(Request $request, $raw = false, Response $entry = nul
{
$this->getKernel()->boot();
$this->getKernel()->getContainer()->set('cache', $this);
$this->getKernel()->getContainer()->set('esi', $this->getEsi());
$this->getKernel()->getContainer()->set($this->getSurrogate()->getName(), $this->getSurrogate());
return parent::forward($request, $raw, $entry);
}
@@ -70,6 +70,18 @@ protected function getOptions()
return array();
}
protected function createSurrogate()
{
return $this->createEsi();
}
/**
* Creates new ESI instance
*
* @return Esi
*
* @deprecated Deprecated since version 2.6, to be removed in 3.0. Use createSurrogate() instead
*/
protected function createEsi()
{
return new Esi();
@@ -10,6 +10,7 @@
<parameter key="fragment.renderer.hinclude.class">Symfony\Bundle\FrameworkBundle\Fragment\ContainerAwareHIncludeFragmentRenderer</parameter>
<parameter key="fragment.renderer.hinclude.global_template"></parameter>
<parameter key="fragment.renderer.esi.class">Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer</parameter>
<parameter key="fragment.renderer.ssi.class">Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer</parameter>
<parameter key="fragment.path">/_fragment</parameter>
</parameters>
@@ -41,5 +42,17 @@
<argument type="service" id="fragment.renderer.inline" />
<call method="setFragmentPath"><argument>%fragment.path%</argument></call>
</service>
<service id="fragment.renderer.ssi" class="%fragment.renderer.ssi.class%">
<tag name="kernel.fragment_renderer" />
<argument type="service" id="ssi" on-invalid="null" />
<argument type="service" id="fragment.renderer.inline" />
<call method="setFragmentPath">
<argument>%fragment.path%</argument>
</call>
<call method="setUriSigner">
<argument type="service" id="uri_signer" />
</call>
</service>
</services>
</container>
@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="ssi.class">Symfony\Component\HttpKernel\HttpCache\Ssi</parameter>
<parameter key="ssi_listener.class">Symfony\Component\HttpKernel\EventListener\SurrogateListener</parameter>
</parameters>
<services>
<service id="ssi" class="%ssi.class%" />
<service id="ssi_listener" class="%ssi_listener.class%">
<tag name="kernel.event_subscriber" />
<argument type="service" id="ssi" on-invalid="ignore" />
</service>
</services>
</container>
@@ -105,6 +105,7 @@ protected static function getBundleDefaultConfig()
'field_name' => '_token',
),
'esi' => array('enabled' => false),
'ssi' => array('enabled' => false),
'fragments' => array(
'enabled' => false,
'path' => '/_fragment',
@@ -11,48 +11,13 @@
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* EsiListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for ESI.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated Deprecated since version 2.6, to be removed in 3.0. Use SurrogateListener instead
*/
class EsiListener implements EventSubscriberInterface
class EsiListener extends SurrogateListener
{
private $esi;
/**
* Constructor.
*
* @param Esi $esi An ESI instance
*/
public function __construct(Esi $esi = null)
{
$this->esi = $esi;
}
/**
* Filters the Response.
*
* @param FilterResponseEvent $event A FilterResponseEvent instance
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest() || null === $this->esi) {
return;
}
$this->esi->addSurrogateControl($event->getResponse());
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => 'onKernelResponse',
);
}
}
@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\EventListener;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SurrogateListener implements EventSubscriberInterface
{
private $surrogate;
/**
* Constructor.
*
* @param SurrogateInterface $surrogate An SurrogateInterface instance
*/
public function __construct(SurrogateInterface $surrogate = null)
{
$this->surrogate = $surrogate;
}
/**
* Filters the Response.
*
* @param FilterResponseEvent $event A FilterResponseEvent instance
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest() || null === $this->surrogate) {
return;
}
$this->surrogate->addSurrogateControl($event->getResponse());
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => 'onKernelResponse',
);
}
}
@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Fragment;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
/**
* Implements Surrogate rendering strategy.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRenderer
{
private $surrogate;
private $inlineStrategy;
/**
* Constructor.
*
* The "fallback" strategy when surrogate is not available should always be an
* instance of InlineFragmentRenderer.
*
* @param SurrogateInterface $surrogate An Surrogate instance
* @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported
*/
public function __construct(SurrogateInterface $surrogate = null, FragmentRendererInterface $inlineStrategy)
{
$this->surrogate = $surrogate;
$this->inlineStrategy = $inlineStrategy;
}
/**
* {@inheritdoc}
*
* Note that if the current Request has no surrogate capability, this method
* falls back to use the inline rendering strategy.
*
* Additional available options:
*
* * alt: an alternative URI to render in case of an error
* * comment: a comment to add when returning the surrogate tag
*
* Note, that not all surrogate strategies support all options. For now
* 'alt' and 'comment' are only supported by ESI.
*
* @see Symfony\Component\HttpKernel\HttpCache\SurrogateInterface
*/
public function render($uri, Request $request, array $options = array())
{
if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) {
return $this->inlineStrategy->render($uri, $request, $options);
}
if ($uri instanceof ControllerReference) {
$uri = $this->generateFragmentUri($uri, $request);
}
$alt = isset($options['alt']) ? $options['alt'] : null;
if ($alt instanceof ControllerReference) {
$alt = $this->generateFragmentUri($alt, $request);
}
$tag = $this->surrogate->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : '');
return new Response($tag);
}
}
Oops, something went wrong.

0 comments on commit bf140a8

Please sign in to comment.