Merge remote branch 'kriswallsmith/assetic/asset-config'

* kriswallsmith/assetic/asset-config:
  Revert "[AsseticBundle] updated configuration to assume values with integer keys are inputs"
  [AsseticBundle] updated configuration to assume values with integer keys are inputs
  [AsseticBundle] made test of route loader less brittle
  [AsseticBundle] added the ability to define assets outside of the view layer
  [AsseticBundle] injected container into factory for better stability
This commit is contained in:
Fabien Potencier 2011-05-14 22:57:26 +02:00
commit 9e407d7e91
10 changed files with 237 additions and 41 deletions

View File

@ -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'])) {

View File

@ -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()

View File

@ -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);
}
}

View File

@ -0,0 +1,29 @@
<?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\Factory\Loader;
use Assetic\Factory\Loader\FormulaLoaderInterface;
use Assetic\Factory\Resource\ResourceInterface;
use Symfony\Bundle\AsseticBundle\Factory\ConfigurationResource;
/**
* Loads configured formulae.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class ConfigurationLoader implements FormulaLoaderInterface
{
public function load(ResourceInterface $resource)
{
return $resource instanceof ConfigurationResource ? $resource->getContent() : array();
}
}

View File

@ -0,0 +1,44 @@
<?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\Factory\Resource;
use Assetic\Factory\Resource\ResourceInterface;
/**
* A configured resource.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
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';
}
}

View File

@ -10,6 +10,8 @@
<parameter key="assetic.asset_manager_cache_warmer.class">Symfony\Bundle\AsseticBundle\CacheWarmer\AssetManagerCacheWarmer</parameter>
<parameter key="assetic.cached_formula_loader.class">Assetic\Factory\Loader\CachedFormulaLoader</parameter>
<parameter key="assetic.config_cache.class">Assetic\Cache\ConfigCache</parameter>
<parameter key="assetic.config_loader.class">Symfony\Bundle\AsseticBundle\Factory\Loader\ConfigurationLoader</parameter>
<parameter key="assetic.config_resource.class">Symfony\Bundle\AsseticBundle\Factory\Resource\ConfigurationResource</parameter>
<parameter key="assetic.coalescing_directory_resource.class">Assetic\Factory\Resource\CoalescingDirectoryResource</parameter>
<parameter key="assetic.directory_resource.class">Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource</parameter>
<parameter key="assetic.filter_manager.class">Symfony\Bundle\AsseticBundle\FilterManager</parameter>
@ -31,9 +33,17 @@
<service id="assetic.asset_factory" class="%assetic.asset_factory.class%" public="false">
<argument type="service" id="kernel" />
<argument type="service" id="service_container" />
<argument>%assetic.read_from%</argument>
<argument>%assetic.debug%</argument>
<call method="setFilterManager"><argument type="service" id="assetic.filter_manager" /></call>
</service>
<service id="assetic.config_loader" class="%assetic.config_loader.class%" public="false">
<tag name="assetic.formula_loader" alias="config" />
</service>
<service id="assetic.config_resource" class="%assetic.config_resource.class%" public="false">
<tag name="assetic.formula_resource" loader="config" />
<argument type="collection" /> <!-- configured formulae -->
</service>
<service id="assetic.config_cache" class="%assetic.config_cache.class%" public="false">

View File

@ -28,6 +28,17 @@
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
<xsd:complexType name="asset">
<xsd:sequence>
<xsd:element name="input" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="filter" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="output" type="xsd:string" />
<xsd:attribute name="debug" type="xsd:string" />
<xsd:anyAttribute namespace="##any" processContents="lax" />
</xsd:complexType>
<xsd:complexType name="filter">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="resource" type="xsd:string" />

View File

@ -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()

View File

@ -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),
);
}
}

View File

@ -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: