Commit 8f05804a authored by Fabien Potencier's avatar Fabien Potencier

feature #803 added support for the Symfony HttpKernel fragment sub-framework (fabpot)

This PR was merged into the master branch.

Discussion
----------

added support for the Symfony HttpKernel fragment sub-framework

Closes #783 and #802

Todo:

 - [x] add some tests

Commits
-------

dcbab7f6 added support for the Symfony HttpKernel fragment sub-framework
parents e0aa6a89 dcbab7f6
Changelog
=========
1.1.2 (2013-XX-XX)
1.2.0 (2013-XX-XX)
------------------
* n/a
* Deprecated TwigCoreExtension (register the new HttpFragmentServiceProvider instead)
* Added HttpFragmentServiceProvider
1.1.1 (2013-10-11)
------------------
......
HttpFragmentServiceProvider
===========================
The *HttpFragmentServiceProvider* provides support for the Symfony2 fragment
sub-framework, which allows you to embed fragments of HTML in a template.
Parameters
----------
* **fragment.path**: The path to use for the URL generated for ESI and
HInclude URLs (``/_fragment`` by default).
* **uri_signer.secret**: The secret to use for the URI signer service (used
for the HInclude renderer).
* **fragment.renderers.hinclude.global_template**: The content or Twig
template to use for the default content when using the HInclude renderer.
Services
--------
* **fragment.handler**: An instance of `FragmentHandler
<http://api.symfony.com/master/Symfony/Component/HttpKernel/Fragment/FragmentHandler.html>`_.
* **fragment.renderers**: An array of fragment renderers (by default, the
inline, ESI, and HInclude renderers are pre-configured).
Registering
-----------
.. code-block:: php
$app->register(new Silex\Provider\HttpFragmentServiceProvider());
Usage
-----
.. note::
This section assumes that you are using Twig for your templates.
Instead of building a page out of a single request/controller/template, the
fragment framework allows you to build a page from several
controllers/sub-requests/sub-templates by using **fragments**.
Including "sub-pages" in the main page can be done with the Twig ``render()``
function:
.. code-block:: jinja
The main page content.
{{ render('/foo') }}
The main page content resumes here.
The ``render()`` call is replaced by the content of the ``/foo`` URL
(internally, a sub-request is handled by Silex to render the sub-page).
Instead of making internal sub-requests, you can also use the ESI (the
sub-request is handled by a reverse proxy) or the HInclude strategies (the
sub-request is handled by a web browser):
.. code-block:: jinja
{{ render(url('route_name')) }}
{{ render_esi(url('route_name')) }}
{{ render_hinclude(url('route_name')) }}
......@@ -14,6 +14,7 @@ Silex
validator
form
http_cache
http_fragment
security
serializer
service_controller
......@@ -16,6 +16,7 @@ use Silex\ServiceProviderInterface;
use Silex\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\HttpKernel\EventListener\EsiListener;
/**
* Symfony HttpKernel component Provider for HTTP cache.
......@@ -38,10 +39,15 @@ class HttpCacheServiceProvider implements ServiceProviderInterface
return new Store($app['http_cache.cache_dir']);
});
$app['http_cache.esi_listener'] = $app->share(function ($app) {
return new EsiListener($app['http_cache.esi']);
});
$app['http_cache.options'] = array();
}
public function boot(Application $app)
{
$app['dispatcher']->addSubscriber($app['http_cache.esi_listener']);
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (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 Silex\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer;
use Symfony\Component\HttpKernel\EventListener\FragmentListener;
use Symfony\Component\HttpKernel\UriSigner;
/**
* HttpKernel Fragment integration for Silex.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpFragmentServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['fragment.handler'] = $app->share(function ($app) {
$handler = new FragmentHandler($app['fragment.renderers'], $app['debug'], $app['request_stack']);
// to be removed when 2.3 is not supported anymore
if (null === $app['request_stack']) {
$handler->setRequest($app['request']);
}
return $handler;
});
$app['fragment.renderer.inline'] = $app->share(function ($app) {
$renderer = new InlineFragmentRenderer($app['kernel'], $app['dispatcher']);
$renderer->setFragmentPath($app['fragment.path']);
return $renderer;
});
$app['fragment.renderer.hinclude'] = $app->share(function ($app) {
$renderer = new HIncludeFragmentRenderer(null, $app['uri_signer'], $app['fragment.renderer.hinclude.global_template'], $app['charset']);
$renderer->setFragmentPath($app['fragment.path']);
return $renderer;
});
$app['fragment.renderer.esi'] = $app->share(function ($app) {
$renderer = new EsiFragmentRenderer($app['http_cache.esi'], $app['fragment.renderer.inline']);
$renderer->setFragmentPath($app['fragment.path']);
return $renderer;
});
$app['fragment.listener'] = $app->share(function ($app) {
return new FragmentListener($app['uri_signer'], $app['fragment.path']);
});
$app['uri_signer'] = $app->share(function ($app) {
return new UriSigner($app['uri_signer.secret']);
});
$app['uri_signer.secret'] = md5(__DIR__);
$app['fragment.path'] = '/_fragment';
$app['fragment.renderer.hinclude.global_template'] = null;
$app['fragment.renderers'] = $app->share(function ($app) {
$renderers = array($app['fragment.renderer.inline'], $app['fragment.renderer.hinclude']);
if (isset($app['http_cache.esi'])) {
$renderers[] = $app['fragment.renderer.esi'];
}
return $renderers;
});
}
public function boot(Application $app)
{
$app['dispatcher']->addSubscriber($app['fragment.listener']);
}
}
......@@ -18,6 +18,8 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
* Twig extension.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated deprecated since 1.2, will be removed in 1.3. Use HttpFragmentServiceProvider instead
*/
class TwigCoreExtension extends \Twig_Extension
{
......
......@@ -18,6 +18,7 @@ use Symfony\Bridge\Twig\Extension\RoutingExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\SecurityExtension;
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Form\TwigRenderer;
......@@ -46,7 +47,6 @@ class TwigServiceProvider implements ServiceProviderInterface
$twig = new \Twig_Environment($app['twig.loader'], $app['twig.options']);
$twig->addGlobal('app', $app);
$twig->addExtension(new TwigCoreExtension());
if ($app['debug']) {
$twig->addExtension(new \Twig_Extension_Debug());
......@@ -65,6 +65,15 @@ class TwigServiceProvider implements ServiceProviderInterface
$twig->addExtension(new SecurityExtension($app['security']));
}
if (isset($app['fragment.handler'])) {
$app['fragment.renderer.hinclude']->setTemplating($twig);
$twig->addExtension(new HttpKernelExtension($app['fragment.handler']));
} else {
// fallback for BC, to be removed in 1.3
$twig->addExtension(new TwigCoreExtension());
}
if (isset($app['form.factory'])) {
$app['twig.form.engine'] = $app->share(function ($app) {
return new TwigRendererEngine($app['twig.form.templates']);
......
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests\Provider;
use Silex\Application;
use Silex\Provider\HttpCacheServiceProvider;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\TwigServiceProvider;
use Symfony\Component\HttpFoundation\Request;
class HttpFragmentServiceProviderTest extends \PHPUnit_Framework_TestCase
{
public function testRenderFunction()
{
$app = new Application();
$app->register(new HttpFragmentServiceProvider());
$app->register(new HttpCacheServiceProvider(), array('http_cache.cache_dir' => sys_get_temp_dir()));
$app->register(new TwigServiceProvider(), array(
'twig.templates' => array(
'hello' => '{{ render("/foo") }}{{ render_esi("/foo") }}{{ render_hinclude("/foo") }}',
'foo' => 'foo',
),
));
$app->get('/hello', function () use ($app) {
return $app['twig']->render('hello');
});
$app->get('/foo', function () use ($app) {
return $app['twig']->render('foo');
});
$response = $app['http_cache']->handle(Request::create('/hello'));
$this->assertEquals('foofoo<hx:include src="/foo"></hx:include>', $response->getContent());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment