[AsseticBundle] updated twig integration to check debug mode at runtime rather than compile time since twig cannot vary its cache by debug mode

This commit is contained in:
Kris Wallsmith 2011-04-21 05:41:45 -07:00
parent 7e33159723
commit 8ad93095d4
15 changed files with 187 additions and 212 deletions

View File

@ -36,13 +36,21 @@ class AsseticController
$this->cache = $cache;
}
public function render($name)
public function render($name, $pos = null)
{
if (!$this->am->has($name)) {
throw new NotFoundHttpException('Asset Not Found');
throw new NotFoundHttpException(sprintf('The "%s" asset could not be found.', $name));
}
$asset = $this->getAsset($name);
if (null !== $pos) {
$leaves = array_values(iterator_to_array($asset));
if (!isset($leaves[$pos])) {
throw new NotFoundHttpException(sprintf('The "%s" asset does not include a leaf at position %d.', $name, $pos));
}
$asset = $leaves[$pos];
}
$response = $this->createResponse();
// last-modified

View File

@ -74,12 +74,10 @@ class AsseticExtension extends Extension
// choose dynamic or static
if ($parameterBag->resolveValue($parameterBag->get('assetic.use_controller'))) {
$loader->load('controller.xml');
$container->setParameter('assetic.twig_extension.class', '%assetic.twig_extension.dynamic.class%');
$container->getDefinition('assetic.helper.dynamic')->addTag('templating.helper', array('alias' => 'assetic'));
$container->removeDefinition('assetic.helper.static');
} else {
$loader->load('asset_writer.xml');
$container->setParameter('assetic.twig_extension.class', '%assetic.twig_extension.static.class%');
$container->getDefinition('assetic.helper.static')->addTag('templating.helper', array('alias' => 'assetic'));
$container->removeDefinition('assetic.helper.dynamic');
}

View File

@ -5,8 +5,7 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.twig_extension.dynamic.class">Symfony\Bundle\AsseticBundle\Twig\DynamicExtension</parameter>
<parameter key="assetic.twig_extension.static.class">Symfony\Bundle\AsseticBundle\Twig\StaticExtension</parameter>
<parameter key="assetic.twig_extension.class">Symfony\Bundle\AsseticBundle\Twig\AsseticExtension</parameter>
<parameter key="assetic.twig_formula_loader.class">Assetic\Extension\Twig\TwigFormulaLoader</parameter>
</parameters>
@ -16,6 +15,7 @@
<tag name="assetic.templating.twig" />
<argument type="service" id="assetic.asset_factory" />
<argument>%assetic.debug%</argument>
<argument>%assetic.use_controller%</argument>
</service>
<service id="assetic.twig_formula_loader" class="%assetic.cached_formula_loader.class%" public="false">
<tag name="assetic.formula_loader" alias="twig" />

View File

@ -11,6 +11,7 @@
namespace Symfony\Bundle\AsseticBundle\Routing;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\LazyAssetManager;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Resource\FileResource;
@ -62,22 +63,40 @@ class AsseticLoader extends Loader
// routes
foreach ($this->am->getNames() as $name) {
$asset = $this->am->get($name);
$formula = $this->am->getFormula($name);
$defaults = array(
'_controller' => 'assetic.controller:render',
'name' => $name,
);
$this->loadRouteForAsset($routes, $asset, $name);
if ($extension = pathinfo($asset->getTargetUrl(), PATHINFO_EXTENSION)) {
$defaults['_format'] = $extension;
// add a route for each "leaf" in debug mode
if (isset($formula[2]['debug']) ? $formula[2]['debug'] : $this->am->isDebug()) {
$i = 0;
foreach ($asset as $leaf) {
$pos = $i++;
$this->loadRouteForAsset($routes, $leaf, $name.'_'.$pos, $pos);
}
}
$routes->add('assetic_'.$name, new Route($asset->getTargetUrl(), $defaults));
}
return $routes;
}
private function loadRouteForAsset(RouteCollection $routes, AssetInterface $asset, $name, $pos = null)
{
$defaults = array(
'_controller' => 'assetic.controller:render',
'name' => $name,
'pos' => $pos,
);
$pattern = $asset->getTargetUrl();
if ($format = pathinfo($pattern, PATHINFO_EXTENSION)) {
$defaults['_format'] = $format;
}
$routes->add('_assetic_'.$name, new Route($pattern, $defaults));
}
public function supports($resource, $type = null)
{
return 'assetic' == $type;

View File

@ -40,6 +40,6 @@ class DynamicAsseticHelper extends AsseticHelper
protected function getAssetUrl(AssetInterface $asset, $options = array())
{
return $this->routerHelper->generate('assetic_'.$options['name']);
return $this->routerHelper->generate('_assetic_'.$options['name']);
}
}

View File

@ -44,7 +44,7 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
}
/**
* @dataProvider provideDebugAndAssetCount
* @dataProvider provideAmDebugAndAssetCount
*/
public function testKernel($debug, $count)
{
@ -55,7 +55,7 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
}
/**
* @dataProvider provideDebugAndAssetCount
* @dataProvider provideRouterDebugAndAssetCount
*/
public function testRoutes($debug, $count)
{
@ -64,7 +64,7 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
$matches = 0;
foreach (array_keys($kernel->getContainer()->get('router')->getRouteCollection()->all()) as $name) {
if (0 === strpos($name, 'assetic_')) {
if (0 === strpos($name, '_assetic_')) {
++$matches;
}
}
@ -102,11 +102,18 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(2, count($crawler->filter('script[src$=".js"]')));
}
public function provideDebugAndAssetCount()
public function provideAmDebugAndAssetCount()
{
// totals include assets defined in both php and twig templates
return array(
array(true, 6),
array(true, 3),
array(false, 3),
);
}
public function provideRouterDebugAndAssetCount()
{
return array(
array(true, 9),
array(false, 3),
);
}

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticExtension as BaseAsseticExtension;
use Assetic\Factory\AssetFactory;
/**
* Assetic extension.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticExtension extends BaseAsseticExtension
{
private $useController;
public function __construct(AssetFactory $factory, $debug = false, $useController = false)
{
parent::__construct($factory, $debug);
$this->useController = $useController;
}
public function getTokenParsers()
{
return array(
new AsseticTokenParser($this->factory, 'javascripts', 'js/*.js', false, array('package')),
new AsseticTokenParser($this->factory, 'stylesheets', 'css/*.css', false, array('package')),
new AsseticTokenParser($this->factory, 'image', 'images/*', true, array('package')),
);
}
public function getGlobals()
{
$globals = parent::getGlobals();
$globals['assetic']['use_controller'] = $this->useController;
return $globals;
}
}

View File

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Asset\AssetInterface;
use Assetic\Extension\Twig\AsseticNode as BaseAsseticNode;
/**
* Assetic node.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticNode extends BaseAsseticNode
{
protected function compileAssetUrl(\Twig_Compiler $compiler, AssetInterface $asset, $name)
{
$compiler
->raw('isset($context[\'assetic\'][\'use_controller\']) && $context[\'assetic\'][\'use_controller\'] ? ')
->subcompile($this->getPathFunction($name))
->raw(' : ')
->subcompile($this->getAssetFunction($asset->getTargetUrl()))
;
}
private function getPathFunction($name)
{
return new \Twig_Node_Expression_Function(
new \Twig_Node_Expression_Name('path', $this->getLine()),
new \Twig_Node(array(new \Twig_Node_Expression_Constant('_assetic_'.$name, $this->getLine()))),
$this->getLine()
);
}
private function getAssetFunction($path)
{
$arguments = array(new \Twig_Node_Expression_Constant($path, $this->getLine()));
if ($this->hasAttribute('package')) {
$arguments[] = new \Twig_Node_Expression_Constant($this->getAttribute('package'), $this->getLine());
}
return new \Twig_Node_Expression_Function(
new \Twig_Node_Expression_Name('asset', $this->getLine()),
new \Twig_Node($arguments),
$this->getLine()
);
}
}

View File

@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Asset\AssetInterface;
use Assetic\Extension\Twig\AsseticTokenParser as BaseAsseticTokenParser;
/**
* Assetic token parser.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticTokenParser extends BaseAsseticTokenParser
{
protected function createNode(AssetInterface $asset, \Twig_NodeInterface $body, array $inputs, array $filters, $name, array $attributes = array(), $lineno = 0, $tag = null)
{
return new AsseticNode($asset, $body, $inputs, $filters, $name, $attributes, $lineno, $tag);
}
}

View File

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticExtension;
use Assetic\Factory\AssetFactory;
/**
* The dynamic extension is used when use_controllers is enabled.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class DynamicExtension extends AsseticExtension
{
public function getTokenParsers()
{
return array(
new DynamicTokenParser($this->factory, 'javascripts', 'js/*.js', $this->debug, false, array('package')),
new DynamicTokenParser($this->factory, 'stylesheets', 'css/*.css', $this->debug, false, array('package')),
new DynamicTokenParser($this->factory, 'image', 'images/*', $this->debug, true, array('package')),
);
}
}

View File

@ -1,36 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticNode;
/**
* The "dynamic" node uses a controller to render assets.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class DynamicNode extends AsseticNode
{
/**
* Renders the asset URL using Symfony's path() function.
*/
protected function getAssetUrlNode(\Twig_NodeInterface $body)
{
return new \Twig_Node_Expression_Function(
new \Twig_Node_Expression_Name('path', $body->getLine()),
new \Twig_Node(array(
new \Twig_Node_Expression_Constant('assetic_'.$this->getAttribute('name'), $body->getLine()),
)),
$body->getLine()
);
}
}

View File

@ -1,27 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticTokenParser;
/**
* Parses an Assetic tag.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class DynamicTokenParser extends AsseticTokenParser
{
static protected function createNode(\Twig_NodeInterface $body, array $inputs, array $filters, array $attributes, $lineno = 0, $tag = null)
{
return new DynamicNode($body, $inputs, $filters, $attributes, $lineno, $tag);
}
}

View File

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticExtension;
use Assetic\Factory\AssetFactory;
/**
* The static extension is used when use_controllers is disabled.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class StaticExtension extends AsseticExtension
{
public function getTokenParsers()
{
return array(
new StaticTokenParser($this->factory, 'javascripts', 'js/*.js', $this->debug, false, array('package')),
new StaticTokenParser($this->factory, 'stylesheets', 'css/*.css', $this->debug, false, array('package')),
new StaticTokenParser($this->factory, 'image', 'images/*', $this->debug, true, array('package')),
);
}
}

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticNode;
/**
* The "static" node references a file in the web directory.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class StaticNode extends AsseticNode
{
/**
* Renders the asset URL using Symfony's asset() function.
*/
protected function getAssetUrlNode(\Twig_NodeInterface $body)
{
return new \Twig_Node_Expression_Function(
new \Twig_Node_Expression_Name('asset', $body->getLine()),
new \Twig_Node(array(
new \Twig_Node_Expression_Constant($this->getAttribute('output'), $body->getLine()),
new \Twig_Node_Expression_Constant($this->hasAttribute('package') ? $this->getAttribute('package') : null, $body->getLine()),
)),
$body->getLine()
);
}
}

View File

@ -1,27 +0,0 @@
<?php
/*
* This file is part of the Symfony 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 Symfony\Bundle\AsseticBundle\Twig;
use Assetic\Extension\Twig\AsseticTokenParser;
/**
* Parses an Assetic tag.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class StaticTokenParser extends AsseticTokenParser
{
static protected function createNode(\Twig_NodeInterface $body, array $inputs, array $filters, array $attributes, $lineno = 0, $tag = null)
{
return new StaticNode($body, $inputs, $filters, $attributes, $lineno, $tag);
}
}