From 57251712e87cfda8af0f9dfa5ccb842c632ec49a Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Mon, 9 May 2011 05:24:47 -0700 Subject: [PATCH 1/5] [AsseticBundle] injected container into factory for better stability --- .../AsseticBundle/Factory/AssetFactory.php | 33 +++++++++++++++++-- .../Resources/config/assetic.xml | 2 +- .../Tests/Factory/AssetFactoryTest.php | 4 ++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/AsseticBundle/Factory/AssetFactory.php b/src/Symfony/Bundle/AsseticBundle/Factory/AssetFactory.php index c3b4aa384b..70a55b80e5 100644 --- a/src/Symfony/Bundle/AsseticBundle/Factory/AssetFactory.php +++ b/src/Symfony/Bundle/AsseticBundle/Factory/AssetFactory.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\AsseticBundle\Factory; use Assetic\Factory\AssetFactory as BaseAssetFactory; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\KernelInterface; /** @@ -21,11 +22,21 @@ use Symfony\Component\HttpKernel\KernelInterface; */ class AssetFactory extends BaseAssetFactory { - protected $kernel; + private $kernel; + private $container; - public function __construct(KernelInterface $kernel, $baseDir, $debug = false) + /** + * Constructor. + * + * @param KernelInterface $kernel The kernel is used to parse bundle notation + * @param ContainerInterface $container The container is used to load the managers lazily, thus avoiding a circular dependency + * @param string $baseDir The base directory for relative inputs + * @param Boolean $debug The current debug mode + */ + public function __construct(KernelInterface $kernel, ContainerInterface $container, $baseDir, $debug = false) { $this->kernel = $kernel; + $this->container = $container; parent::__construct($baseDir, $debug); } @@ -51,4 +62,22 @@ class AssetFactory extends BaseAssetFactory return parent::parseInput($input); } + + protected function createAssetReference($name) + { + if (!$this->getAssetManager()) { + $this->setAssetManager($this->container->get('assetic.asset_manager')); + } + + return parent::createAssetReference($name); + } + + protected function getFilter($name) + { + if (!$this->getFilterManager()) { + $this->setFilterManager($this->container->get('assetic.filter_manager')); + } + + return parent::getFilter($name); + } } diff --git a/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml b/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml index 23d67202d6..e072ee1da8 100644 --- a/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml +++ b/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml @@ -31,9 +31,9 @@ + %assetic.read_from% %assetic.debug% - diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/Factory/AssetFactoryTest.php b/src/Symfony/Bundle/AsseticBundle/Tests/Factory/AssetFactoryTest.php index dcb3ef94e8..9b48f39c41 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/Factory/AssetFactoryTest.php +++ b/src/Symfony/Bundle/AsseticBundle/Tests/Factory/AssetFactoryTest.php @@ -17,6 +17,7 @@ class AssetFactoryTest extends \PHPUnit_Framework_TestCase { protected $kernel; protected $factory; + protected $container; protected function setUp() { @@ -25,7 +26,8 @@ class AssetFactoryTest extends \PHPUnit_Framework_TestCase } $this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface'); - $this->factory = new AssetFactory($this->kernel, '/path/to/web'); + $this->container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface'); + $this->factory = new AssetFactory($this->kernel, $this->container, '/path/to/web'); } public function testBundleNotation() From e8e87e65f7ad1ba58508b8d8fee8b9c52214aa1e Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Mon, 9 May 2011 05:40:14 -0700 Subject: [PATCH 2/5] [AsseticBundle] added the ability to define assets outside of the view layer In config.yml: assetic: assets: jquery: js/jquery.js plugin1: - @jquery - js/jquery.plugin1.js all_js: - @plugin1 filters: ?yui_js all_css: - css/*.scss filters: [ scss, ?yui_css ] filters: yui_css: jar: %kernel.root_dir%/Resources/java/yui.jar yui_js: jar: %kernel.root_dir%/Resources/java/yui.jar scss: ~ In Twig: {% javascripts '@all_js' %} {% endjavascripts %} {% stylesheets '@all_css' %} {% endstylesheets %} --- .../DependencyInjection/AsseticExtension.php | 13 +++++ .../DependencyInjection/Configuration.php | 55 +++++++++++++++++++ .../Factory/Loader/ConfigurationLoader.php | 29 ++++++++++ .../Resource/ConfigurationResource.php | 44 +++++++++++++++ .../Resources/config/assetic.xml | 10 ++++ .../Resources/config/schema/assetic-1.0.xsd | 11 ++++ .../Tests/Resources/config/config.yml | 15 ++++- 7 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/AsseticBundle/Factory/Loader/ConfigurationLoader.php create mode 100644 src/Symfony/Bundle/AsseticBundle/Factory/Resource/ConfigurationResource.php diff --git a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php index 99e7d82b6b..38c49dc327 100644 --- a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php +++ b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/AsseticExtension.php @@ -52,6 +52,19 @@ class AsseticExtension extends Extension $container->setParameter('assetic.node.bin', $config['node']); $container->setParameter('assetic.sass.bin', $config['sass']); + // register formulae + $formulae = array(); + foreach ($config['assets'] as $name => $formula) { + $formulae[$name] = array($formula['inputs'], $formula['filters'], $formula['options']); + } + + if ($formulae) { + $container->getDefinition('assetic.config_resource')->replaceArgument(0, $formulae); + } else { + $container->removeDefinition('assetic.config_loader'); + $container->removeDefinition('assetic.config_resource'); + } + // register filters foreach ($config['filters'] as $name => $filter) { if (isset($filter['resource'])) { diff --git a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php index 07dcedaf86..9e0f31dbf7 100644 --- a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php @@ -77,6 +77,61 @@ class Configuration implements ConfigurationInterface ->end() ->end() + // assets + ->fixXmlConfig('asset') + ->children() + ->arrayNode('assets') + ->addDefaultsIfNotSet() + ->requiresAtLeastOneElement() + ->useAttributeAsKey('name') + ->prototype('array') + ->beforeNormalization() + // a scalar is a simple formula of one input file + ->ifTrue(function($v) { return !is_array($v); }) + ->then(function($v) { return array('inputs' => array($v)); }) + ->end() + ->beforeNormalization() + ->always() + ->then(function($v) + { + // cast scalars as array + foreach (array('input', 'inputs', 'filter', 'filters') as $key) { + if (isset($v[$key]) && !is_array($v[$key])) { + $v[$key] = array($v[$key]); + } + } + + // organize arbitrary options + foreach ($v as $key => $value) { + if (!in_array($key, array('input', 'inputs', 'filter', 'filters', 'option', 'options'))) { + $v['options'][$key] = $value; + unset($v[$key]); + } + } + + return $v; + }) + ->end() + + // the formula + ->fixXmlConfig('input') + ->fixXmlConfig('filter') + ->children() + ->arrayNode('inputs') + ->prototype('scalar')->end() + ->end() + ->arrayNode('filters') + ->prototype('scalar')->end() + ->end() + ->arrayNode('options') + ->useAttributeAsKey('name') + ->prototype('variable')->end() + ->end() + ->end() + ->end() + ->end() + ->end() + // filters ->fixXmlConfig('filter') ->children() diff --git a/src/Symfony/Bundle/AsseticBundle/Factory/Loader/ConfigurationLoader.php b/src/Symfony/Bundle/AsseticBundle/Factory/Loader/ConfigurationLoader.php new file mode 100644 index 0000000000..8466c3678b --- /dev/null +++ b/src/Symfony/Bundle/AsseticBundle/Factory/Loader/ConfigurationLoader.php @@ -0,0 +1,29 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Symfony\Bundle\AsseticBundle\Factory\Loader; + +use Assetic\Factory\Loader\FormulaLoaderInterface; +use Assetic\Factory\Resource\ResourceInterface; +use Symfony\Bundle\AsseticBundle\Factory\ConfigurationResource; + +/** + * Loads configured formulae. + * + * @author Kris Wallsmith + */ +class ConfigurationLoader implements FormulaLoaderInterface +{ + public function load(ResourceInterface $resource) + { + return $resource instanceof ConfigurationResource ? $resource->getContent() : array(); + } +} diff --git a/src/Symfony/Bundle/AsseticBundle/Factory/Resource/ConfigurationResource.php b/src/Symfony/Bundle/AsseticBundle/Factory/Resource/ConfigurationResource.php new file mode 100644 index 0000000000..e1fac48b47 --- /dev/null +++ b/src/Symfony/Bundle/AsseticBundle/Factory/Resource/ConfigurationResource.php @@ -0,0 +1,44 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Symfony\Bundle\AsseticBundle\Factory\Resource; + +use Assetic\Factory\Resource\ResourceInterface; + +/** + * A configured resource. + * + * @author Kris Wallsmith + */ +class ConfigurationResource implements ResourceInterface +{ + private $formulae; + + public function __construct(array $formulae) + { + $this->formulae = $formulae; + } + + public function isFresh($timestamp) + { + return true; + } + + public function getContent() + { + return $this->formulae; + } + + public function __toString() + { + return 'symfony'; + } +} diff --git a/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml b/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml index e072ee1da8..8d0c56671c 100644 --- a/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml +++ b/src/Symfony/Bundle/AsseticBundle/Resources/config/assetic.xml @@ -10,6 +10,8 @@ Symfony\Bundle\AsseticBundle\CacheWarmer\AssetManagerCacheWarmer Assetic\Factory\Loader\CachedFormulaLoader Assetic\Cache\ConfigCache + Symfony\Bundle\AsseticBundle\Factory\Loader\ConfigurationLoader + Symfony\Bundle\AsseticBundle\Factory\Resource\ConfigurationResource Assetic\Factory\Resource\CoalescingDirectoryResource Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource Symfony\Bundle\AsseticBundle\FilterManager @@ -36,6 +38,14 @@ %assetic.debug% + + + + + + + + %assetic.cache_dir%/config diff --git a/src/Symfony/Bundle/AsseticBundle/Resources/config/schema/assetic-1.0.xsd b/src/Symfony/Bundle/AsseticBundle/Resources/config/schema/assetic-1.0.xsd index e2928fd13a..0f3f6a262c 100644 --- a/src/Symfony/Bundle/AsseticBundle/Resources/config/schema/assetic-1.0.xsd +++ b/src/Symfony/Bundle/AsseticBundle/Resources/config/schema/assetic-1.0.xsd @@ -28,6 +28,17 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml index 2ec6299560..3e1377b998 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml +++ b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml @@ -18,8 +18,21 @@ twig: assetic: use_controller: true read_from: "%kernel.root_dir%/web" - bundles: [TestBundle] + bundles: [ TestBundle ] + assets: + jquery: js/jquery.js + app_css: + inputs: + - css/main.css + - css/more.css + - @widget_css + filters: [ ?yui_css ] + output: css/packed/app.css + widget_css: + inputs: css/widget.sass + filters: sass filters: + sass: ~ yui_css: jar: %kernel.root_dir/java/yui-compressor-2.4.6.jar twig: From 94bd1c465599d375bb641a2baeb7c46bd3ea86b0 Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Mon, 9 May 2011 06:32:06 -0700 Subject: [PATCH 3/5] [AsseticBundle] made test of route loader less brittle --- .../AsseticBundle/Tests/FunctionalTest.php | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php b/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php index 3c9ba424ff..266844744d 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php +++ b/src/Symfony/Bundle/AsseticBundle/Tests/FunctionalTest.php @@ -43,33 +43,39 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase $filesystem->remove($this->cacheDir); } - /** - * @dataProvider provideAmDebugAndAssetCount - */ - public function testKernel($debug, $count) + public function testRoutes() { - $kernel = new TestKernel('test', $debug); + $countRoutes = function($router) + { + $count = 0; + foreach ($router->getRouteCollection()->all() as $name => $route) { + if (0 === strpos($name, '_assetic_')) { + ++$count; + } + } + + return $count; + }; + + $kernel = new TestKernel('test', false); $kernel->boot(); - $this->assertEquals($count, count($kernel->getContainer()->get('assetic.asset_manager')->getNames())); - } + $am = $kernel->getContainer()->get('assetic.asset_manager'); + $names = $am->getNames(); + $baseline = $expected = count($names); - /** - * @dataProvider provideRouterDebugAndAssetCount - */ - public function testRoutes($debug, $count) - { - $kernel = new TestKernel('test', $debug); - $kernel->boot(); - - $matches = 0; - foreach (array_keys($kernel->getContainer()->get('router')->getRouteCollection()->all()) as $name) { - if (0 === strpos($name, '_assetic_')) { - ++$matches; + foreach ($names as $name) { + $asset = $am->get($name); + foreach ($asset as $leaf) { + ++$expected; } } - $this->assertEquals($count, $matches); + $this->assertEquals($baseline, $countRoutes($kernel->getContainer()->get('router'))); + + $kernel = new TestKernel('test', true); + $kernel->boot(); + $this->assertEquals($expected, $countRoutes($kernel->getContainer()->get('router'))); } public function testTwigRenderDebug() @@ -101,20 +107,4 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase $this->assertEquals(3, count($crawler->filter('link[href$=".css"]'))); $this->assertEquals(2, count($crawler->filter('script[src$=".js"]'))); } - - public function provideAmDebugAndAssetCount() - { - return array( - array(true, 3), - array(false, 3), - ); - } - - public function provideRouterDebugAndAssetCount() - { - return array( - array(true, 9), - array(false, 3), - ); - } } From fb104cedf86edd605efd7475bc35193fa7c76f2b Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Mon, 9 May 2011 08:14:00 -0700 Subject: [PATCH 4/5] [AsseticBundle] updated configuration to assume values with integer keys are inputs --- .../AsseticBundle/DependencyInjection/Configuration.php | 8 ++++++-- .../AsseticBundle/Tests/Resources/config/config.yml | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php index 9e0f31dbf7..ecb159070e 100644 --- a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php @@ -101,9 +101,13 @@ class Configuration implements ConfigurationInterface } } - // organize arbitrary options + // organize inputs and arbitrary options + $inputsKey = isset($v['input']) ? 'input' : 'inputs'; foreach ($v as $key => $value) { - if (!in_array($key, array('input', 'inputs', 'filter', 'filters', 'option', 'options'))) { + if (is_integer($key)) { + $v[$inputsKey][] = $value; + unset($v[$key]); + } elseif (!in_array($key, array('input', 'inputs', 'filter', 'filters', 'option', 'options'))) { $v['options'][$key] = $value; unset($v[$key]); } diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml index 3e1377b998..9ad2702372 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml +++ b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml @@ -21,6 +21,10 @@ assetic: bundles: [ TestBundle ] assets: jquery: js/jquery.js + foo: + - foo.css + - bar.css + filters: ?yui_css app_css: inputs: - css/main.css From b25750daa9404c6a47cd88685e1c58e6ba6dc934 Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Mon, 9 May 2011 14:58:30 -0700 Subject: [PATCH 5/5] Revert "[AsseticBundle] updated configuration to assume values with integer keys are inputs" This reverts commit fb104cedf86edd605efd7475bc35193fa7c76f2b. --- .../AsseticBundle/DependencyInjection/Configuration.php | 8 ++------ .../AsseticBundle/Tests/Resources/config/config.yml | 4 ---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php index ecb159070e..9e0f31dbf7 100644 --- a/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/AsseticBundle/DependencyInjection/Configuration.php @@ -101,13 +101,9 @@ class Configuration implements ConfigurationInterface } } - // organize inputs and arbitrary options - $inputsKey = isset($v['input']) ? 'input' : 'inputs'; + // organize arbitrary options foreach ($v as $key => $value) { - if (is_integer($key)) { - $v[$inputsKey][] = $value; - unset($v[$key]); - } elseif (!in_array($key, array('input', 'inputs', 'filter', 'filters', 'option', 'options'))) { + if (!in_array($key, array('input', 'inputs', 'filter', 'filters', 'option', 'options'))) { $v['options'][$key] = $value; unset($v[$key]); } diff --git a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml index 9ad2702372..3e1377b998 100644 --- a/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml +++ b/src/Symfony/Bundle/AsseticBundle/Tests/Resources/config/config.yml @@ -21,10 +21,6 @@ assetic: bundles: [ TestBundle ] assets: jquery: js/jquery.js - foo: - - foo.css - - bar.css - filters: ?yui_css app_css: inputs: - css/main.css