diff --git a/src/Symfony/Bundle/AsseticBundle/Controller/AsseticController.php b/src/Symfony/Bundle/AsseticBundle/Controller/AsseticController.php index b34a845241..136ef133d6 100644 --- a/src/Symfony/Bundle/AsseticBundle/Controller/AsseticController.php +++ b/src/Symfony/Bundle/AsseticBundle/Controller/AsseticController.php @@ -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 diff --git a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php index 19213c6aee..1284628dde 100644 --- a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php +++ b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php @@ -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'); } diff --git a/src/Symfony/Bundle/AsseticBundle/Resources/config/templating_twig.xml b/src/Symfony/Bundle/AsseticBundle/Resources/config/templating_twig.xml index 5e3d070eb4..a2340dc316 100644 --- a/src/Symfony/Bundle/AsseticBundle/Resources/config/templating_twig.xml +++ b/src/Symfony/Bundle/AsseticBundle/Resources/config/templating_twig.xml @@ -5,8 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - Symfony\Bundle\AsseticBundle\Twig\DynamicExtension - Symfony\Bundle\AsseticBundle\Twig\StaticExtension + Symfony\Bundle\AsseticBundle\Twig\AsseticExtension Assetic\Extension\Twig\TwigFormulaLoader @@ -16,6 +15,7 @@ %assetic.debug% + %assetic.use_controller% diff --git a/src/Symfony/Bundle/AsseticBundle/Routing/AsseticLoader.php b/src/Symfony/Bundle/AsseticBundle/Routing/AsseticLoader.php index 763ef31be4..214c9bc8fe 100644 --- a/src/Symfony/Bundle/AsseticBundle/Routing/AsseticLoader.php +++ b/src/Symfony/Bundle/AsseticBundle/Routing/AsseticLoader.php @@ -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; diff --git a/src/Symfony/Bundle/AsseticBundle/Templating/DynamicAsseticHelper.php b/src/Symfony/Bundle/AsseticBundle/Templating/DynamicAsseticHelper.php index e1ad188abe..a3dad04501 100644 --- a/src/Symfony/Bundle/AsseticBundle/Templating/DynamicAsseticHelper.php +++ b/src/Symfony/Bundle/AsseticBundle/Templating/DynamicAsseticHelper.php @@ -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']); } } diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php b/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php index 76a6c600a0..3c9ba424ff 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php +++ b/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php @@ -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), ); } diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/AsseticExtension.php b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticExtension.php new file mode 100644 index 0000000000..e5302ed71c --- /dev/null +++ b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticExtension.php @@ -0,0 +1,49 @@ + + * + * 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 + */ +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; + } +} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/AsseticNode.php b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticNode.php new file mode 100644 index 0000000000..1202b4abe0 --- /dev/null +++ b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticNode.php @@ -0,0 +1,57 @@ + + * + * 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 + */ +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() + ); + } +} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/AsseticTokenParser.php b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticTokenParser.php new file mode 100644 index 0000000000..fc0673ea24 --- /dev/null +++ b/src/Symfony/Bundle/AsseticBundle/Twig/AsseticTokenParser.php @@ -0,0 +1,28 @@ + + * + * 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 + */ +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); + } +} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicExtension.php b/src/Symfony/Bundle/AsseticBundle/Twig/DynamicExtension.php deleted file mode 100644 index fc95aec740..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicExtension.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * 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 - */ -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')), - ); - } -} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicNode.php b/src/Symfony/Bundle/AsseticBundle/Twig/DynamicNode.php deleted file mode 100644 index b17c0d0541..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicNode.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * 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 - */ -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() - ); - } -} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicTokenParser.php b/src/Symfony/Bundle/AsseticBundle/Twig/DynamicTokenParser.php deleted file mode 100644 index 418b48d50e..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/DynamicTokenParser.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * 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 - */ -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); - } -} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/StaticExtension.php b/src/Symfony/Bundle/AsseticBundle/Twig/StaticExtension.php deleted file mode 100644 index 884e6c7f24..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/StaticExtension.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * 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 - */ -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')), - ); - } -} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/StaticNode.php b/src/Symfony/Bundle/AsseticBundle/Twig/StaticNode.php deleted file mode 100644 index 73f0fe383f..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/StaticNode.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * 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 - */ -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() - ); - } -} diff --git a/src/Symfony/Bundle/AsseticBundle/Twig/StaticTokenParser.php b/src/Symfony/Bundle/AsseticBundle/Twig/StaticTokenParser.php deleted file mode 100644 index 5ee21b8ec7..0000000000 --- a/src/Symfony/Bundle/AsseticBundle/Twig/StaticTokenParser.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * 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 - */ -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); - } -}