Initial commit with Symfony 2.1+Vendors

Signed-off-by: Gergely POLONKAI (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely
2012-07-01 09:52:20 +02:00
commit 082a0130c2
5381 changed files with 416709 additions and 0 deletions

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;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\TemplateResourcesPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\AssetFactoryPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\AssetManagerPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\CheckYuiFilterPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\FilterManagerPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\CheckCssEmbedFilterPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\CheckClosureFilterPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\TemplatingPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\SprocketsFilterPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\RouterResourcePass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Assetic integration.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new TemplateResourcesPass());
$container->addCompilerPass(new CheckClosureFilterPass());
$container->addCompilerPass(new CheckCssEmbedFilterPass());
$container->addCompilerPass(new CheckYuiFilterPass());
$container->addCompilerPass(new SprocketsFilterPass());
$container->addCompilerPass(new TemplatingPass());
$container->addCompilerPass(new AssetFactoryPass());
$container->addCompilerPass(new AssetManagerPass());
$container->addCompilerPass(new FilterManagerPass());
$container->addCompilerPass(new RouterResourcePass());
}
}

View File

@@ -0,0 +1,41 @@
<?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\CacheWarmer;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The AssetManagerCacheWarmer warms up the formula loader.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AssetManagerCacheWarmer implements CacheWarmerInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function warmUp($cacheDir)
{
$am = $this->container->get('assetic.asset_manager');
$am->load();
}
public function isOptional()
{
return true;
}
}

View File

@@ -0,0 +1,232 @@
<?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\Command;
use Assetic\Util\PathUtils;
use Assetic\AssetWriter;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\LazyAssetManager;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Dumps assets to the filesystem.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class DumpCommand extends ContainerAwareCommand
{
private $basePath;
private $verbose;
private $am;
protected function configure()
{
$this
->setName('assetic:dump')
->setDescription('Dumps all assets to the filesystem')
->addArgument('write_to', InputArgument::OPTIONAL, 'Override the configured asset root')
->addOption('watch', null, InputOption::VALUE_NONE, 'Check for changes every second, debug mode only')
->addOption('force', null, InputOption::VALUE_NONE, 'Force an initial generation of all assets (used with --watch)')
->addOption('period', null, InputOption::VALUE_REQUIRED, 'Set the polling period in seconds (used with --watch)', 1)
;
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output);
$this->basePath = $input->getArgument('write_to') ?: $this->getContainer()->getParameter('assetic.write_to');
$this->verbose = $input->getOption('verbose');
$this->am = $this->getContainer()->get('assetic.asset_manager');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln(sprintf('Dumping all <comment>%s</comment> assets.', $input->getOption('env')));
$output->writeln(sprintf('Debug mode is <comment>%s</comment>.', $input->getOption('no-debug') ? 'off' : 'on'));
$output->writeln('');
if (!$input->getOption('watch')) {
foreach ($this->am->getNames() as $name) {
$this->dumpAsset($name, $output);
}
return;
}
if (!$this->am->isDebug()) {
throw new \RuntimeException('The --watch option is only available in debug mode.');
}
$this->watch($input, $output);
}
/**
* Watches a asset manager for changes.
*
* This method includes an infinite loop the continuously polls the asset
* manager for changes.
*
* @param InputInterface $input The command input
* @param OutputInterface $output The command output
*/
private function watch(InputInterface $input, OutputInterface $output)
{
$refl = new \ReflectionClass('Assetic\\AssetManager');
$prop = $refl->getProperty('assets');
$prop->setAccessible(true);
$cache = sys_get_temp_dir().'/assetic_watch_'.substr(sha1($this->basePath), 0, 7);
if ($input->getOption('force') || !file_exists($cache)) {
$previously = array();
} else {
$previously = unserialize(file_get_contents($cache));
}
$error = '';
while (true) {
try {
foreach ($this->am->getNames() as $name) {
if ($this->checkAsset($name, $previously)) {
$this->dumpAsset($name, $output);
}
}
// reset the asset manager
$prop->setValue($this->am, array());
$this->am->load();
file_put_contents($cache, serialize($previously));
$error = '';
sleep($input->getOption('period'));
} catch (\Exception $e) {
if ($error != $msg = $e->getMessage()) {
$output->writeln('<error>[error]</error> '.$msg);
$error = $msg;
}
}
}
}
/**
* Checks if an asset should be dumped.
*
* @param string $name The asset name
* @param array &$previously An array of previous visits
*
* @return Boolean Whether the asset should be dumped
*/
private function checkAsset($name, array &$previously)
{
$formula = $this->am->hasFormula($name) ? serialize($this->am->getFormula($name)) : null;
$asset = $this->am->get($name);
$mtime = $asset->getLastModified();
if (isset($previously[$name])) {
$changed = $previously[$name]['mtime'] != $mtime || $previously[$name]['formula'] != $formula;
} else {
$changed = true;
}
$previously[$name] = array('mtime' => $mtime, 'formula' => $formula);
return $changed;
}
/**
* Writes an asset.
*
* If the application or asset is in debug mode, each leaf asset will be
* dumped as well.
*
* @param string $name An asset name
* @param OutputInterface $output The command output
*/
private function dumpAsset($name, OutputInterface $output)
{
$asset = $this->am->get($name);
$formula = $this->am->getFormula($name);
// start by dumping the main asset
$this->doDump($asset, $output);
// dump each leaf if debug
if (isset($formula[2]['debug']) ? $formula[2]['debug'] : $this->am->isDebug()) {
foreach ($asset as $leaf) {
$this->doDump($leaf, $output);
}
}
}
/**
* Performs the asset dump.
*
* @param AssetInterface $asset An asset
* @param OutputInterface $output The command output
*
* @throws RuntimeException If there is a problem writing the asset
*/
private function doDump(AssetInterface $asset, OutputInterface $output)
{
$writer = new AssetWriter(sys_get_temp_dir(), $this->getContainer()->getParameter('assetic.variables'));
$ref = new \ReflectionMethod($writer, 'getCombinations');
$ref->setAccessible(true);
$combinations = $ref->invoke($writer, $asset->getVars());
foreach ($combinations as $combination) {
$asset->setValues($combination);
$target = rtrim($this->basePath, '/').'/'.str_replace('_controller/', '',
PathUtils::resolvePath($asset->getTargetPath(), $asset->getVars(),
$asset->getValues()));
if (!is_dir($dir = dirname($target))) {
$output->writeln(sprintf(
'<comment>%s</comment> <info>[dir+]</info> %s',
date('H:i:s'),
$dir
));
if (false === @mkdir($dir, 0777, true)) {
throw new \RuntimeException('Unable to create directory '.$dir);
}
}
$output->writeln(sprintf(
'<comment>%s</comment> <info>[file+]</info> %s',
date('H:i:s'),
$target
));
if ($this->verbose) {
if ($asset instanceof \Traversable) {
foreach ($asset as $leaf) {
$root = $leaf->getSourceRoot();
$path = $leaf->getSourcePath();
$output->writeln(sprintf(' <comment>%s/%s</comment>', $root ?: '[unknown root]', $path ?: '[unknown path]'));
}
} else {
$root = $asset->getSourceRoot();
$path = $asset->getSourcePath();
$output->writeln(sprintf(' <comment>%s/%s</comment>', $root ?: '[unknown root]', $path ?: '[unknown path]'));
}
}
if (false === @file_put_contents($target, $asset->dump())) {
throw new \RuntimeException('Unable to write file '.$target);
}
}
}
}

View File

@@ -0,0 +1,75 @@
<?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\Config;
use Assetic\Factory\Resource\ResourceInterface as AsseticResourceInterface;
use Symfony\Component\Config\Resource\ResourceInterface as SymfonyResourceInterface;
/**
* Turns an Assetic resource into a Symfony one.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticResource implements SymfonyResourceInterface
{
private $resource;
public function __construct(AsseticResourceInterface $resource)
{
$this->resource = $resource;
}
public function __toString()
{
return (string) $this->resource;
}
public function isFresh($timestamp)
{
return $this->resource->isFresh($timestamp);
}
/**
* Returns the Assetic resource.
*
* @return AsseticResourceInterface The wrapped Assetic resource
*/
public function getResource()
{
return $this->resource;
}
public function exists()
{
return true;
}
public function getId()
{
return md5('assetic'.$this->resource);
}
public function getModificationTime()
{
return -1;
}
public function serialize()
{
return serialize($this->resource);
}
public function unserialize($serialized)
{
$this->resource = unserialize($serialized);
}
}

View File

@@ -0,0 +1,121 @@
<?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\Controller;
use Assetic\ValueSupplierInterface;
use Assetic\Asset\AssetCache;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\LazyAssetManager;
use Assetic\Cache\CacheInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Profiler\Profiler;
/**
* Serves assets.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticController
{
protected $request;
protected $am;
protected $cache;
protected $enableProfiler;
protected $profiler;
protected $valueSupplier;
public function __construct(Request $request, LazyAssetManager $am, CacheInterface $cache, $enableProfiler = false, Profiler $profiler = null)
{
$this->request = $request;
$this->am = $am;
$this->cache = $cache;
$this->enableProfiler = (boolean) $enableProfiler;
$this->profiler = $profiler;
}
public function setValueSupplier(ValueSupplierInterface $supplier)
{
$this->valueSupplier = $supplier;
}
public function render($name, $pos = null)
{
if (!$this->enableProfiler && null !== $this->profiler) {
$this->profiler->disable();
}
if (!$this->am->has($name)) {
throw new NotFoundHttpException(sprintf('The "%s" asset could not be found.', $name));
}
$asset = $this->am->get($name);
if (null !== $pos && !$asset = $this->findAssetLeaf($asset, $pos)) {
throw new NotFoundHttpException(sprintf('The "%s" asset does not include a leaf at position %d.', $name, $pos));
}
$response = $this->createResponse();
$response->setExpires(new \DateTime());
// last-modified
if (null !== $lastModified = $asset->getLastModified()) {
$date = new \DateTime();
$date->setTimestamp($lastModified);
$response->setLastModified($date);
}
// etag
if ($this->am->hasFormula($name)) {
$formula = $this->am->getFormula($name);
$formula['last_modified'] = $lastModified;
$response->setETag(md5(serialize($formula)));
}
if ($response->isNotModified($this->request)) {
return $response;
}
$response->setContent($this->cachifyAsset($asset)->dump());
return $response;
}
protected function createResponse()
{
return new Response();
}
protected function cachifyAsset(AssetInterface $asset)
{
if ($vars = $asset->getVars()) {
if (null === $this->valueSupplier) {
throw new \RuntimeException(sprintf('You must configure a value supplier if you have assets with variables.'));
}
$asset->setValues(array_intersect_key($this->valueSupplier->getValues(), array_flip($vars)));
}
return new AssetCache($asset, $this->cache);
}
private function findAssetLeaf(\Traversable $asset, $pos)
{
$i = 0;
foreach ($asset as $leaf) {
if ($pos == $i++) {
return $leaf;
}
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Symfony\Bundle\AsseticBundle;
use Assetic\ValueSupplierInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Default Value Supplier.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class DefaultValueSupplier implements ValueSupplierInterface
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getValues()
{
if (!$this->container->isScopeActive('request')) {
return array();
}
$request = $this->container->get('request');
return array(
'locale' => $request->getLocale(),
'env' => $this->container->getParameter('kernel.environment'),
);
}
}

View File

@@ -0,0 +1,144 @@
<?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\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* Semantic asset configuration.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticExtension extends Extension
{
/**
* Loads the configuration.
*
* @param array $configs An array of configuration settings
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('assetic.xml');
$loader->load('templating_twig.xml');
$loader->load('templating_php.xml');
$processor = new Processor();
$configuration = $this->getConfiguration($configs, $container);
$config = $processor->processConfiguration($configuration, $configs);
$container->setParameter('assetic.debug', $config['debug']);
$container->setParameter('assetic.use_controller', $config['use_controller']['enabled']);
$container->setParameter('assetic.enable_profiler', $config['use_controller']['profiler']);
$container->setParameter('assetic.read_from', $config['read_from']);
$container->setParameter('assetic.write_to', $config['write_to']);
$container->setParameter('assetic.variables', $config['variables']);
$container->setParameter('assetic.java.bin', $config['java']);
$container->setParameter('assetic.node.bin', $config['node']);
$container->setParameter('assetic.ruby.bin', $config['ruby']);
$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'])) {
$loader->load($container->getParameterBag()->resolveValue($filter['resource']));
unset($filter['resource']);
} else {
$loader->load('filters/'.$name.'.xml');
}
if (isset($filter['file'])) {
$container->getDefinition('assetic.filter.'.$name)->setFile($filter['file']);
unset($filter['file']);
}
if (isset($filter['apply_to'])) {
if (!is_array($filter['apply_to'])) {
$filter['apply_to'] = array($filter['apply_to']);
}
foreach ($filter['apply_to'] as $i => $pattern) {
$worker = new DefinitionDecorator('assetic.worker.ensure_filter');
$worker->replaceArgument(0, '/'.$pattern.'/');
$worker->replaceArgument(1, new Reference('assetic.filter.'.$name));
$worker->addTag('assetic.factory_worker');
$container->setDefinition('assetic.filter.'.$name.'.worker'.$i, $worker);
}
unset($filter['apply_to']);
}
foreach ($filter as $key => $value) {
$container->setParameter('assetic.filter.'.$name.'.'.$key, $value);
}
}
// twig functions
$container->setParameter('assetic.twig_extension.functions', $config['twig']['functions']);
// choose dynamic or static
if ($useController = $container->getParameterBag()->resolveValue($container->getParameterBag()->get('assetic.use_controller'))) {
$loader->load('controller.xml');
$container->getDefinition('assetic.helper.dynamic')->addTag('templating.helper', array('alias' => 'assetic'));
$container->removeDefinition('assetic.helper.static');
} else {
$container->getDefinition('assetic.helper.static')->addTag('templating.helper', array('alias' => 'assetic'));
$container->removeDefinition('assetic.helper.dynamic');
}
$container->setParameter('assetic.bundles', $config['bundles']);
}
/**
* Returns the base path for the XSD files.
*
* @return string The XSD base path
*/
public function getXsdValidationBasePath()
{
return __DIR__ . '/../Resources/config/schema';
}
public function getNamespace()
{
return 'http://symfony.com/schema/dic/assetic';
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
$bundles = $container->getParameter('kernel.bundles');
return new Configuration(array_keys($bundles));
}
}

View File

@@ -0,0 +1,36 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds services tagged as workers to the asset factory.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AssetFactoryPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.asset_factory')) {
return;
}
$factory = $container->getDefinition('assetic.asset_factory');
foreach ($container->findTaggedServiceIds('assetic.factory_worker') as $id => $attr) {
$factory->addMethodCall('addWorker', array(new Reference($id)));
}
}
}

View File

@@ -0,0 +1,62 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds services tagged as assets to the asset manager.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AssetManagerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.asset_manager')) {
return;
}
$am = $container->getDefinition('assetic.asset_manager');
// add assets
foreach ($container->findTaggedServiceIds('assetic.asset') as $id => $attributes) {
foreach ($attributes as $attr) {
if (isset($attr['alias'])) {
$am->addMethodCall('set', array($attr['alias'], new Reference($id)));
}
}
}
// add loaders
$loaders = array();
foreach ($container->findTaggedServiceIds('assetic.formula_loader') as $id => $attributes) {
foreach ($attributes as $attr) {
if (isset($attr['alias'])) {
$loaders[$attr['alias']] = new Reference($id);
}
}
}
$am->replaceArgument(1, $loaders);
// add resources
foreach ($container->findTaggedServiceIds('assetic.formula_resource') as $id => $attributes) {
foreach ($attributes as $attr) {
if (isset($attr['loader'])) {
$am->addMethodCall('addResource', array(new Reference($id), $attr['loader']));
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Tags either the closure JAR or API filter for the filter manager.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class CheckClosureFilterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->hasDefinition('assetic.filter.closure.jar')
&& $container->hasParameter('assetic.filter.closure.jar')
&& $container->getParameterBag()->resolveValue($container->getParameter('assetic.filter.closure.jar'))) {
$container->removeDefinition('assetic.filter.closure.api');
$container->setAlias('assetic.filter.closure', 'assetic.filter.closure.jar');
} elseif ($container->hasDefinition('assetic.filter.closure.api')) {
$container->removeDefinition('assetic.filter.closure.jar');
$container->setAlias('assetic.filter.closure', 'assetic.filter.closure.api');
}
}
}

View File

@@ -0,0 +1,31 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Checks that the location of the CssEmbed JAR has been configured.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class CheckCssEmbedFilterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->hasDefinition('assetic.filter.cssembed') &&
!$container->getParameterBag()->resolveValue($container->getParameter('assetic.filter.cssembed.jar'))) {
throw new \RuntimeException('The "assetic.filters.cssembed" configuration requires a "jar" value.');
}
}
}

View File

@@ -0,0 +1,36 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Checks that the location of the YUI JAR has been configured.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class CheckYuiFilterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->hasDefinition('assetic.filter.yui_css') &&
!$container->getParameterBag()->resolveValue($container->getParameter('assetic.filter.yui_css.jar'))) {
throw new \RuntimeException('The "assetic.filters.yui_css" configuration requires a "jar" value.');
}
if ($container->hasDefinition('assetic.filter.yui_js') &&
!$container->getParameterBag()->resolveValue($container->getParameter('assetic.filter.yui_js.jar'))) {
throw new \RuntimeException('The "assetic.filters.yui_js" configuration requires a "jar" value.');
}
}
}

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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Adds services tagged as filters to the filter manager.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class FilterManagerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.filter_manager')) {
return;
}
$mapping = array();
foreach ($container->findTaggedServiceIds('assetic.filter') as $id => $attributes) {
foreach ($attributes as $attr) {
if (isset($attr['alias'])) {
$mapping[$attr['alias']] = $id;
}
}
}
$container
->getDefinition('assetic.filter_manager')
->replaceArgument(1, $mapping);
}
}

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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\Yaml\Yaml;
/**
* This pass adds Assetic routes when use_controller is true.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class RouterResourcePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->getParameter('assetic.use_controller') || !$container->getParameter('router.resource')) {
return;
}
$file = $container->getParameter('kernel.cache_dir').'/assetic/routing.yml';
if (!is_dir($dir = dirname($file))) {
mkdir($dir, 0777, true);
}
file_put_contents($file, Yaml::dump(array(
'_assetic' => array('resource' => '.', 'type' => 'assetic'),
'_app' => array('resource' => $container->getParameter('router.resource')),
)));
$container->setParameter('router.resource', $file);
}
}

View File

@@ -0,0 +1,35 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Finishes configuration of the Sprockets filter.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class SprocketsFilterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.filter.sprockets')) {
return;
}
$filter = $container->getDefinition('assetic.filter.sprockets');
foreach ($container->getParameter('assetic.filter.sprockets.include_dirs') as $dir) {
$filter->addMethodCall('addIncludeDir', array($dir));
}
}
}

View File

@@ -0,0 +1,67 @@
<?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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Bundle\AsseticBundle\DependencyInjection\DirectoryResourceDefinition;
/**
* This pass adds directory resources to scan for assetic assets.
*
* @author Kris Wallsmith <kris@symfony.com>
* @author Lukas Kahwe Smith <smith@pooteeweet.org>
*/
class TemplateResourcesPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.asset_manager')) {
return;
}
$engines = $container->getParameter('templating.engines');
// bundle and kernel resources
$bundles = $container->getParameter('kernel.bundles');
$asseticBundles = $container->getParameterBag()->resolveValue($container->getParameter('assetic.bundles'));
foreach ($asseticBundles as $bundleName) {
$rc = new \ReflectionClass($bundles[$bundleName]);
foreach ($engines as $engine) {
$this->setBundleDirectoryResources($container, $engine, dirname($rc->getFileName()), $bundleName);
}
}
foreach ($engines as $engine) {
$this->setAppDirectoryResources($container, $engine);
}
}
protected function setBundleDirectoryResources(ContainerBuilder $container, $engine, $bundleDirName, $bundleName)
{
$container->setDefinition(
'assetic.'.$engine.'_directory_resource.'.$bundleName,
new DirectoryResourceDefinition($bundleName, $engine, array(
$container->getParameter('kernel.root_dir').'/Resources/'.$bundleName.'/views',
$bundleDirName.'/Resources/views',
))
);
}
protected function setAppDirectoryResources(ContainerBuilder $container, $engine)
{
$container->setDefinition(
'assetic.'.$engine.'_directory_resource.kernel',
new DirectoryResourceDefinition('', $engine, array($container->getParameter('kernel.root_dir').'/Resources/views'))
);
}
}

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\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* This pass removes services associated with unused templating engines.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class TemplatingPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('assetic.asset_manager')) {
return;
}
$engines = $container->getParameterBag()->resolveValue($container->getParameter('templating.engines'));
if (!in_array('twig', $engines)) {
foreach ($container->findTaggedServiceIds('assetic.templating.twig') as $id => $attr) {
$container->removeDefinition($id);
}
}
if (!in_array('php', $engines)) {
foreach ($container->findTaggedServiceIds('assetic.templating.php') as $id => $attr) {
$container->removeDefinition($id);
}
}
}
}

View File

@@ -0,0 +1,199 @@
<?php
/*
* This file is part of the Symfony package.
*
* (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 Symfony\Bundle\AsseticBundle\DependencyInjection;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This class contains the configuration information for the bundle
*
* This information is solely responsible for how the different configuration
* sections are normalized, and merged.
*
* @author Christophe Coevoet <stof@notk.org>
* @author Kris Wallsmith <kris@symfony.com>
*/
class Configuration implements ConfigurationInterface
{
private $bundles;
/**
* Constructor
*
* @param array $bundles An array of bundle names
*/
public function __construct(array $bundles)
{
$this->bundles = $bundles;
}
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
public function getConfigTreeBuilder()
{
$builder = new TreeBuilder();
$finder = new ExecutableFinder();
$builder->root('assetic')
->children()
->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
->arrayNode('use_controller')
->addDefaultsIfNotSet()
->treatTrueLike(array('enabled' => true))
->treatFalseLike(array('enabled' => false))
->children()
->booleanNode('enabled')->defaultValue('%kernel.debug%')->end()
->booleanNode('profiler')->defaultFalse()->end()
->end()
->end()
->scalarNode('read_from')->defaultValue('%kernel.root_dir%/../web')->end()
->scalarNode('write_to')->defaultValue('%assetic.read_from%')->end()
->scalarNode('java')->defaultValue(function() use($finder) { return $finder->find('java', '/usr/bin/java'); })->end()
->scalarNode('node')->defaultValue(function() use($finder) { return $finder->find('node', '/usr/bin/node'); })->end()
->scalarNode('ruby')->defaultValue(function() use($finder) { return $finder->find('ruby', '/usr/bin/ruby'); })->end()
->scalarNode('sass')->defaultValue(function() use($finder) { return $finder->find('sass', '/usr/bin/sass'); })->end()
->end()
// variables
->fixXmlConfig('variable')
->children()
->arrayNode('variables')
->useAttributeAsKey('name')
->prototype('array')
->prototype('scalar')->end()
->end()
->end()
->end()
// bundles
->fixXmlConfig('bundle')
->children()
->arrayNode('bundles')
->defaultValue($this->bundles)
->prototype('scalar')
->validate()
->ifNotInArray($this->bundles)
->thenInvalid('%s is not a valid bundle.')
->end()
->end()
->end()
->end()
// assets
->fixXmlConfig('asset')
->children()
->arrayNode('assets')
->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()
->arrayNode('filters')
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->prototype('variable')
->treatNullLike(array())
->validate()
->ifTrue(function($v) { return !is_array($v); })
->thenInvalid('The assetic.filters config %s must be either null or an array.')
->end()
->end()
->validate()
->always(function($v) use ($finder) {
if (isset($v['compass']) && !isset($v['compass']['bin'])) {
$v['compass']['bin'] = $finder->find('compass', '/usr/bin/compass');
}
return $v;
})
->end()
->end()
->end()
// twig
->children()
->arrayNode('twig')
->addDefaultsIfNotSet()
->fixXmlConfig('function')
->children()
->arrayNode('functions')
->defaultValue(array())
->useAttributeAsKey('name')
->prototype('variable')
->treatNullLike(array())
->validate()
->ifTrue(function($v) { return !is_array($v); })
->thenInvalid('The assetic.twig.functions config %s must be either null or an array.')
->end()
->end()
->end()
->end()
->end()
->end()
;
return $builder;
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (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 Symfony\Bundle\AsseticBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Encapsulates logic for creating a directory resource.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class DirectoryResourceDefinition extends Definition
{
/**
* Constructor.
*
* @param string $bundle A bundle name or empty string
* @param string $engine The templating engine
* @param array $dirs An array of directories to merge
*/
public function __construct($bundle, $engine, array $dirs)
{
if (!count($dirs)) {
throw new \InvalidArgumentException('You must provide at least one directory.');
}
parent::__construct();
$this
->addTag('assetic.templating.'.$engine)
->addTag('assetic.formula_resource', array('loader' => $engine));
;
if (1 == count($dirs)) {
// no need to coalesce
self::configureDefinition($this, $bundle, $engine, reset($dirs));
return;
}
// gather the wrapped resource definitions
$resources = array();
foreach ($dirs as $dir) {
$resources[] = $resource = new Definition();
self::configureDefinition($resource, $bundle, $engine, $dir);
}
$this
->setClass('%assetic.coalescing_directory_resource.class%')
->addArgument($resources)
->setPublic(false)
;
}
static private function configureDefinition(Definition $definition, $bundle, $engine, $dir)
{
$definition
->setClass('%assetic.directory_resource.class%')
->addArgument(new Reference('templating.loader'))
->addArgument($bundle)
->addArgument($dir)
->addArgument('/\.[^.]+\.'.$engine.'$/')
->setPublic(false)
;
}
}

View File

@@ -0,0 +1,31 @@
<?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\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
/**
* Adds a few formats to each request.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class RequestListener
{
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$request->setFormat('png', 'image/png');
$request->setFormat('jpg', 'image/jpeg');
$request->setFormat('gif', 'image/gif');
}
}

View File

@@ -0,0 +1,26 @@
<?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\Exception;
class InvalidBundleException extends \LogicException
{
public function __construct($bundle, $usage, $template, array $enabled, $code = 0, \Exception $previous = null)
{
$message = sprintf('You must add %s to the assetic.bundle config to use %s in %s.', $bundle, $usage, $template);
if ($enabled) {
$message .= sprintf(' (currently enabled: %s)', implode(', ', $enabled));
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,97 @@
<?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;
use Assetic\Factory\AssetFactory as BaseAssetFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpKernel\KernelInterface;
/**
* Loads asset formulae from the filesystem.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AssetFactory extends BaseAssetFactory
{
private $kernel;
private $container;
private $parameterBag;
/**
* 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 ParameterBagInterface $parameterBag The container parameter bag
* @param string $baseDir The base directory for relative inputs
* @param Boolean $debug The current debug mode
*/
public function __construct(KernelInterface $kernel, ContainerInterface $container, ParameterBagInterface $parameterBag, $baseDir, $debug = false)
{
$this->kernel = $kernel;
$this->container = $container;
$this->parameterBag = $parameterBag;
parent::__construct($baseDir, $debug);
}
/**
* Adds support for bundle notation file and glob assets and parameter placeholders.
*
* FIXME: This is a naive implementation of globs in that it doesn't
* attempt to support bundle inheritance within the glob pattern itself.
*/
protected function parseInput($input, array $options = array())
{
$input = $this->parameterBag->resolveValue($input);
// expand bundle notation
if ('@' == $input[0] && false !== strpos($input, '/')) {
// use the bundle path as this asset's root
$bundle = substr($input, 1);
if (false !== $pos = strpos($bundle, '/')) {
$bundle = substr($bundle, 0, $pos);
}
$options['root'] = array($this->kernel->getBundle($bundle)->getPath());
// canonicalize the input
if (false !== $pos = strpos($input, '*')) {
// locateResource() does not support globs so we provide a naive implementation here
list($before, $after) = explode('*', $input, 2);
$input = $this->kernel->locateResource($before).'*'.$after;
} else {
$input = $this->kernel->locateResource($input);
}
}
return parent::parseInput($input, $options);
}
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,87 @@
<?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\BasePhpFormulaLoader;
/**
* Loads formulae from Symfony2 PHP templates.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticHelperFormulaLoader extends BasePhpFormulaLoader
{
protected function registerPrototypes()
{
return array(
'$view[\'assetic\']->javascripts(*)' => array('output' => 'js/*.js'),
'$view[\'assetic\']->stylesheets(*)' => array('output' => 'css/*.css'),
'$view[\'assetic\']->image(*)' => array('output' => 'images/*', 'single' => true),
'$view["assetic"]->javascripts(*)' => array('output' => 'js/*.js'),
'$view["assetic"]->stylesheets(*)' => array('output' => 'css/*.css'),
'$view["assetic"]->image(*)' => array('output' => 'images/*', 'single' => true),
'$view->get(\'assetic\')->javascripts(*)' => array('output' => 'js/*.js'),
'$view->get(\'assetic\')->stylesheets(*)' => array('output' => 'css/*.css'),
'$view->get(\'assetic\')->image(*)' => array('output' => 'images/*', 'single' => true),
'$view->get("assetic")->javascripts(*)' => array('output' => 'js/*.js'),
'$view->get("assetic")->stylesheets(*)' => array('output' => 'css/*.css'),
'$view->get("assetic")->image(*)' => array('output' => 'images/*', 'single' => true),
);
}
protected function registerSetupCode()
{
return <<<'EOF'
class Helper
{
public function assets()
{
global $_call;
$_call = func_get_args();
}
public function javascripts()
{
global $_call;
$_call = func_get_args();
}
public function stylesheets()
{
global $_call;
$_call = func_get_args();
}
public function image()
{
global $_call;
$_call = func_get_args();
}
}
class View extends ArrayObject
{
public function __construct(Helper $helper)
{
parent::__construct(array('assetic' => $helper));
}
public function get()
{
return $this['assetic'];
}
}
$view = new View(new Helper());
EOF;
}
}

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\Resource\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,30 @@
<?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\CoalescingDirectoryResource as BaseCoalescingDirectoryResource;
use Assetic\Factory\Resource\ResourceInterface;
/**
* Coalesces multiple directories together into one merged resource.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class CoalescingDirectoryResource extends BaseCoalescingDirectoryResource
{
protected function getRelativeName(ResourceInterface $file, ResourceInterface $directory)
{
$name = (string) $file;
return substr($name, strpos($name, ':'));
}
}

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

@@ -0,0 +1,51 @@
<?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\DirectoryResource as BaseDirectoryResource;
use Symfony\Component\Templating\Loader\LoaderInterface;
/**
* A directory resource that creates Symfony2 templating resources.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class DirectoryResource extends BaseDirectoryResource
{
protected $loader;
protected $bundle;
protected $path;
/**
* Constructor.
*
* @param LoaderInterface $loader The templating loader
* @param string $bundle The current bundle name
* @param string $path The directory path
* @param string $pattern A regex pattern for file basenames
*/
public function __construct(LoaderInterface $loader, $bundle, $path, $pattern = null)
{
$this->loader = $loader;
$this->bundle = $bundle;
$this->path = rtrim($path, '/').'/';
parent::__construct($path, $pattern);
}
public function getIterator()
{
return is_dir($this->path)
? new DirectoryResourceIterator($this->loader, $this->bundle, $this->path, $this->getInnerIterator())
: new \EmptyIterator();
}
}

View File

@@ -0,0 +1,45 @@
<?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 Symfony\Component\Templating\Loader\LoaderInterface;
class DirectoryResourceIterator extends \RecursiveIteratorIterator
{
protected $loader;
protected $bundle;
protected $path;
/**
* Constructor.
*
* @param LoaderInterface $loader The templating loader
* @param string $bundle The current bundle name
* @param string $path The directory
* @param RecursiveIterator $iterator The inner iterator
*/
public function __construct(LoaderInterface $loader, $bundle, $path, \RecursiveIterator $iterator)
{
$this->loader = $loader;
$this->bundle = $bundle;
$this->path = $path;
parent::__construct($iterator);
}
public function current()
{
$file = parent::current();
return new FileResource($this->loader, $this->bundle, $this->path, $file->getPathname());
}
}

View File

@@ -0,0 +1,88 @@
<?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;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Component\Templating\Loader\LoaderInterface;
/**
* A file resource.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class FileResource implements ResourceInterface
{
protected $loader;
protected $bundle;
protected $baseDir;
protected $path;
protected $template;
/**
* Constructor.
*
* @param LoaderInterface $loader The templating loader
* @param string $bundle The current bundle name
* @param string $baseDir The directory
* @param string $path The file path
*/
public function __construct(LoaderInterface $loader, $bundle, $baseDir, $path)
{
$this->loader = $loader;
$this->bundle = $bundle;
$this->baseDir = $baseDir;
$this->path = $path;
}
public function isFresh($timestamp)
{
return $this->loader->isFresh($this->getTemplate(), $timestamp);
}
public function getContent()
{
$templateReference = $this->getTemplate();
$fileResource = $this->loader->load($templateReference);
if (!$fileResource) {
throw new \InvalidArgumentException(sprintf('Unable to find template "%s".', $templateReference));
}
return $fileResource->getContent();
}
public function __toString()
{
return (string) $this->getTemplate();
}
protected function getTemplate()
{
if (null === $this->template) {
$this->template = self::createTemplateReference($this->bundle, substr($this->path, strlen($this->baseDir)));
}
return $this->template;
}
static private function createTemplateReference($bundle, $file)
{
$parts = explode('/', strtr($file, '\\', '/'));
$elements = explode('.', array_pop($parts));
$engine = array_pop($elements);
$format = array_pop($elements);
$name = implode('.', $elements);
return new TemplateReference($bundle, implode('/', $parts), $name, $format, $engine);
}
}

View File

@@ -0,0 +1,33 @@
<?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\Worker;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\Worker\WorkerInterface;
/**
* Prepends a fake front controller so the asset knows where it is-ish.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class UseControllerWorker implements WorkerInterface
{
public function process(AssetInterface $asset)
{
$targetUrl = $asset->getTargetPath();
if ($targetUrl && '/' != $targetUrl[0] && 0 !== strpos($targetUrl, '_controller/')) {
$asset->setTargetPath('_controller/'.$targetUrl);
}
return $asset;
}
}

View File

@@ -0,0 +1,55 @@
<?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;
use Assetic\FilterManager as BaseFilterManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Lazy filter manager.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class FilterManager extends BaseFilterManager
{
protected $container;
protected $mappings;
/**
* Constructor.
*
* @param ContainerInterface $container The service container
* @param array $mappings A hash of filter names to service ids
*/
public function __construct(ContainerInterface $container, array $mappings)
{
$this->container = $container;
$this->mappings = $mappings;
}
public function get($name)
{
return isset($this->mappings[$name])
? $this->container->get($this->mappings[$name])
: parent::get($name);
}
public function has($name)
{
return isset($this->mappings[$name]) || parent::has($name);
}
public function getNames()
{
return array_unique(array_merge(array_keys($this->mappings), parent::getNames()));
}
}

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.asset_factory.class">Symfony\Bundle\AsseticBundle\Factory\AssetFactory</parameter>
<parameter key="assetic.asset_manager.class">Assetic\Factory\LazyAssetManager</parameter>
<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">Symfony\Bundle\AsseticBundle\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>
<parameter key="assetic.worker.ensure_filter.class">Assetic\Factory\Worker\EnsureFilterWorker</parameter>
<parameter key="assetic.value_supplier.class">Symfony\Bundle\AsseticBundle\DefaultValueSupplier</parameter>
<parameter key="assetic.node.paths" type="collection"></parameter>
<parameter key="assetic.cache_dir">%kernel.cache_dir%/assetic</parameter>
<parameter key="assetic.bundles" type="collection"></parameter>
</parameters>
<services>
<!-- managers -->
<service id="assetic.filter_manager" class="%assetic.filter_manager.class%">
<argument type="service" id="service_container" />
<argument type="collection"></argument>
</service>
<service id="assetic.asset_manager" class="%assetic.asset_manager.class%">
<argument type="service" id="assetic.asset_factory" />
<argument type="collection"></argument>
</service>
<service id="assetic.asset_factory" class="%assetic.asset_factory.class%" public="false">
<argument type="service" id="kernel" />
<argument type="service" id="service_container" />
<argument type="service" id="assetic.parameter_bag" />
<argument>%assetic.read_from%</argument>
<argument>%assetic.debug%</argument>
</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">
<argument>%assetic.cache_dir%/config</argument>
</service>
<service id="assetic.asset_manager_cache_warmer" class="%assetic.asset_manager_cache_warmer.class%" public="false">
<tag name="kernel.cache_warmer" priority="10" />
<argument type="service" id="service_container" />
</service>
<service id="assetic.worker.ensure_filter" class="%assetic.worker.ensure_filter.class%" abstract="true" public="false">
<argument /> <!-- pattern -->
<argument /> <!-- filter -->
</service>
<service id="assetic.parameter_bag" class="Symfony\Component\DependencyInjection\ParameterBag\ParameterBag" public="false">
<argument type="service" id="assetic.parameters" />
</service>
<service id="assetic.parameters" class="stdClass" factory-service="service_container" factory-method="getDefaultParameters" public="false" />
<service id="assetic.value_supplier.default" class="%assetic.value_supplier.class%" public="false">
<argument type="service" id="service_container" />
</service>
<service id="assetic.value_supplier" alias="assetic.value_supplier.default" public="false" />
</services>
</container>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.controller.class">Symfony\Bundle\AsseticBundle\Controller\AsseticController</parameter>
<parameter key="assetic.routing_loader.class">Symfony\Bundle\AsseticBundle\Routing\AsseticLoader</parameter>
<parameter key="assetic.cache.class">Assetic\Cache\FilesystemCache</parameter>
<parameter key="assetic.use_controller_worker.class">Symfony\Bundle\AsseticBundle\Factory\Worker\UseControllerWorker</parameter>
<parameter key="assetic.request_listener.class">Symfony\Bundle\AsseticBundle\EventListener\RequestListener</parameter>
</parameters>
<services>
<service id="assetic.routing_loader" class="%assetic.routing_loader.class%" public="false">
<tag name="routing.loader" />
<argument type="service" id="assetic.asset_manager" />
</service>
<service id="assetic.controller" class="%assetic.controller.class%" scope="prototype">
<argument type="service" id="request" />
<argument type="service" id="assetic.asset_manager" />
<argument type="service" id="assetic.cache" />
<argument>%assetic.enable_profiler%</argument>
<argument type="service" id="profiler" on-invalid="null" />
<call method="setValueSupplier">
<argument type="service" id="assetic.value_supplier" on-invalid="ignore" />
</call>
</service>
<service id="assetic.cache" class="%assetic.cache.class%" public="false">
<argument>%assetic.cache_dir%/assets</argument>
</service>
<service id="assetic.use_controller_worker" class="%assetic.use_controller_worker.class%" public="false">
<tag name="assetic.factory_worker" />
</service>
<service id="assetic.request_listener" class="%assetic.request_listener.class%">
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
</service>
</services>
</container>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.closure.api.class">Assetic\Filter\GoogleClosure\CompilerApiFilter</parameter>
<parameter key="assetic.filter.closure.jar.class">Assetic\Filter\GoogleClosure\CompilerJarFilter</parameter>
<parameter key="assetic.filter.closure.java">%assetic.java.bin%</parameter>
<parameter key="assetic.filter.closure.compilation_level">null</parameter>
</parameters>
<services>
<service id="assetic.filter.closure.jar" class="%assetic.filter.closure.jar.class%">
<tag name="assetic.filter" alias="closure" />
<argument>%assetic.filter.closure.jar%</argument>
<argument>%assetic.filter.closure.java%</argument>
<call method="setCompilationLevel">
<argument>%assetic.filter.closure.compilation_level%</argument>
</call>
</service>
<service id="assetic.filter.closure.api" class="%assetic.filter.closure.api.class%">
<tag name="assetic.filter" alias="closure" />
<call method="setCompilationLevel">
<argument>%assetic.filter.closure.compilation_level%</argument>
</call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.coffee.class">Assetic\Filter\CoffeeScriptFilter</parameter>
<parameter key="assetic.filter.coffee.bin">/usr/bin/coffee</parameter>
<parameter key="assetic.filter.coffee.node">%assetic.node.bin%</parameter>
<parameter key="assetic.filter.coffee.bare">null</parameter>
</parameters>
<services>
<service id="assetic.filter.coffee" class="%assetic.filter.coffee.class%">
<tag name="assetic.filter" alias="coffee" />
<argument>%assetic.filter.coffee.bin%</argument>
<argument>%assetic.filter.coffee.node%</argument>
<call method="setBare"><argument>%assetic.filter.coffee.bare%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.compass.class">Assetic\Filter\CompassFilter</parameter>
<parameter key="assetic.filter.compass.bin">/usr/bin/compass</parameter>
<parameter key="assetic.filter.compass.debug">false</parameter>
<parameter key="assetic.filter.compass.style">null</parameter>
<parameter key="assetic.filter.compass.images_dir">null</parameter>
<parameter key="assetic.filter.compass.javascripts_dir">null</parameter>
<parameter key="assetic.filter.compass.http_path">null</parameter>
<parameter key="assetic.filter.compass.http_images_path">null</parameter>
<parameter key="assetic.filter.compass.generated_images_path">null</parameter>
<parameter key="assetic.filter.compass.http_javascripts_path">null</parameter>
<parameter key="assetic.filter.compass.plugins" type="collection" />
</parameters>
<services>
<service id="assetic.filter.compass" class="%assetic.filter.compass.class%">
<tag name="assetic.filter" alias="compass" />
<argument>%assetic.filter.compass.bin%</argument>
<call method="setDebugInfo"><argument>%assetic.filter.compass.debug%</argument></call>
<call method="setStyle"><argument>%assetic.filter.compass.style%</argument></call>
<call method="setImagesDir"><argument>%assetic.filter.compass.images_dir%</argument></call>
<call method="setJavascriptsDir"><argument>%assetic.filter.compass.javascripts_dir%</argument></call>
<call method="setHttpPath"><argument>%assetic.filter.compass.http_path%</argument></call>
<call method="setHttpImagesPath"><argument>%assetic.filter.compass.http_images_path%</argument></call>
<call method="setGeneratedImagesPath"><argument>%assetic.filter.compass.generated_images_path%</argument></call>
<call method="setHttpJavascriptsPath"><argument>%assetic.filter.compass.http_javascripts_path%</argument></call>
<call method="setPlugins"><argument>%assetic.filter.compass.plugins%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.cssembed.class">Assetic\Filter\CssEmbedFilter</parameter>
<parameter key="assetic.filter.cssembed.java">%assetic.java.bin%</parameter>
<parameter key="assetic.filter.cssembed.jar" />
<parameter key="assetic.filter.cssembed.charset">%kernel.charset%</parameter>
<parameter key="assetic.filter.cssembed.mhtml">false</parameter>
<parameter key="assetic.filter.cssembed.mhtml_root">null</parameter>
<parameter key="assetic.filter.cssembed.root">null</parameter>
<parameter key="assetic.filter.cssembed.skip_missing">false</parameter>
<parameter key="assetic.filter.cssembed.max_uri_length">null</parameter>
<parameter key="assetic.filter.cssembed.max_image_size">null</parameter>
</parameters>
<services>
<service id="assetic.filter.cssembed" class="%assetic.filter.cssembed.class%">
<tag name="assetic.filter" alias="cssembed" />
<argument>%assetic.filter.cssembed.jar%</argument>
<argument>%assetic.filter.cssembed.java%</argument>
<call method="setCharset"><argument>%assetic.filter.cssembed.charset%</argument></call>
<call method="setMhtml"><argument>%assetic.filter.cssembed.mhtml%</argument></call>
<call method="setMhtmlRoot"><argument>%assetic.filter.cssembed.mhtml_root%</argument></call>
<call method="setRoot"><argument>%assetic.filter.cssembed.root%</argument></call>
<call method="setSkipMissing"><argument>%assetic.filter.cssembed.skip_missing%</argument></call>
<call method="setMaxUriLength"><argument>%assetic.filter.cssembed.max_uri_length%</argument></call>
<call method="setMaxImageSize"><argument>%assetic.filter.cssembed.max_image_size%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.cssimport.class">Assetic\Filter\CssImportFilter</parameter>
</parameters>
<services>
<service id="assetic.filter.cssimport" class="%assetic.filter.cssimport.class%">
<tag name="assetic.filter" alias="cssimport" />
</service>
</services>
</container>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.cssmin.class">Assetic\Filter\CssMinFilter</parameter>
<parameter key="assetic.filter.cssmin.filters" type="collection" />
<parameter key="assetic.filter.cssmin.plugins" type="collection" />
</parameters>
<services>
<service id="assetic.filter.cssmin" class="%assetic.filter.cssmin.class%">
<tag name="assetic.filter" alias="cssmin" />
<call method="setFilters"><argument>%assetic.filter.cssmin.filters%</argument></call>
<call method="setPlugins"><argument>%assetic.filter.cssmin.plugins%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.cssrewrite.class">Assetic\Filter\CssRewriteFilter</parameter>
</parameters>
<services>
<service id="assetic.filter.cssrewrite" class="%assetic.filter.cssrewrite.class%">
<tag name="assetic.filter" alias="cssrewrite" />
</service>
</services>
</container>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.gss.class">Assetic\Filter\GssFilter</parameter>
<parameter key="assetic.filter.gss.java">%assetic.java.bin%</parameter>
<parameter key="assetic.filter.gss.jar" />
</parameters>
<services>
<service id="assetic.filter.gss" class="%assetic.filter.gss.class%">
<tag name="assetic.filter" alias="gss" />
<argument>%assetic.filter.gss.jar%</argument>
<argument>%assetic.filter.gss.java%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.jpegoptim.class">Assetic\Filter\JpegoptimFilter</parameter>
<parameter key="assetic.filter.jpegoptim.bin">/usr/bin/jpegoptim</parameter>
<parameter key="assetic.filter.jpegoptim.strip_all">false</parameter>
<parameter key="assetic.filter.jpegoptim.max">null</parameter>
</parameters>
<services>
<service id="assetic.filter.jpegoptim" class="%assetic.filter.jpegoptim.class%">
<tag name="assetic.filter" alias="jpegoptim" />
<argument>%assetic.filter.jpegoptim.bin%</argument>
<call method="setStripAll"><argument>%assetic.filter.jpegoptim.strip_all%</argument></call>
<call method="setMax"><argument>%assetic.filter.jpegoptim.max%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.jpegtran.class">Assetic\Filter\JpegtranFilter</parameter>
<parameter key="assetic.filter.jpegtran.bin">/usr/bin/jpegtran</parameter>
<parameter key="assetic.filter.jpegtran.copy">null</parameter>
<parameter key="assetic.filter.jpegtran.optimize">false</parameter>
<parameter key="assetic.filter.jpegtran.progressive">false</parameter>
<parameter key="assetic.filter.jpegtran.restart">null</parameter>
</parameters>
<services>
<service id="assetic.filter.jpegtran" class="%assetic.filter.jpegtran.class%">
<tag name="assetic.filter" alias="jpegtran" />
<argument>%assetic.filter.jpegtran.bin%</argument>
<call method="setCopy"><argument>%assetic.filter.jpegtran.copy%</argument></call>
<call method="setOptimize"><argument>%assetic.filter.jpegtran.optimize%</argument></call>
<call method="setProgressive"><argument>%assetic.filter.jpegtran.progressive%</argument></call>
<call method="setRestart"><argument>%assetic.filter.jpegtran.restart%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.less.class">Assetic\Filter\LessFilter</parameter>
<parameter key="assetic.filter.less.node">%assetic.node.bin%</parameter>
<parameter key="assetic.filter.less.node_paths">%assetic.node.paths%</parameter>
<parameter key="assetic.filter.less.compress">null</parameter>
</parameters>
<services>
<service id="assetic.filter.less" class="%assetic.filter.less.class%">
<tag name="assetic.filter" alias="less" />
<argument>%assetic.filter.less.node%</argument>
<argument>%assetic.filter.less.node_paths%</argument>
<call method="setCompress"><argument>%assetic.filter.less.compress%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.lessphp.class">Assetic\Filter\LessphpFilter</parameter>
<parameter key="assetic.filter.lessphp.presets" type="collection"></parameter>
</parameters>
<services>
<service id="assetic.filter.lessphp" class="%assetic.filter.lessphp.class%">
<tag name="assetic.filter" alias="lessphp" />
<call method="setPresets"><argument>%assetic.filter.lessphp.presets%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.optipng.class">Assetic\Filter\OptiPngFilter</parameter>
<parameter key="assetic.filter.optipng.bin">/usr/bin/optipng</parameter>
<parameter key="assetic.filter.optipng.level">null</parameter>
</parameters>
<services>
<service id="assetic.filter.optipng" class="%assetic.filter.optipng.class%">
<tag name="assetic.filter" alias="optipng" />
<argument>%assetic.filter.optipng.bin%</argument>
<call method="setLevel"><argument>%assetic.filter.optipng.level%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.packager.class">Assetic\Filter\PackagerFilter</parameter>
<parameter key="assetic.filter.packager.packages" type="collection" />
</parameters>
<services>
<service id="assetic.filter.packager" class="%assetic.filter.packager.class%">
<tag name="assetic.filter" alias="packager" />
<argument>%assetic.filter.packager.packages%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.pngout.class">Assetic\Filter\PngoutFilter</parameter>
<parameter key="assetic.filter.pngout.bin">/usr/bin/pngout</parameter>
<parameter key="assetic.filter.pngout.color">null</parameter>
<parameter key="assetic.filter.pngout.filter">null</parameter>
<parameter key="assetic.filter.pngout.strategy">null</parameter>
<parameter key="assetic.filter.pngout.block_split_threshold">null</parameter>
</parameters>
<services>
<service id="assetic.filter.pngout" class="%assetic.filter.pngout.class%">
<tag name="assetic.filter" alias="pngout" />
<argument>%assetic.filter.pngout.bin%</argument>
<call method="setColor"><argument>%assetic.filter.pngout.color%</argument></call>
<call method="setFilter"><argument>%assetic.filter.pngout.filter%</argument></call>
<call method="setStrategy"><argument>%assetic.filter.pngout.strategy%</argument></call>
<call method="setBlockSplitThreshold"><argument>%assetic.filter.pngout.block_split_threshold%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.sass.class">Assetic\Filter\Sass\SassFilter</parameter>
<parameter key="assetic.filter.sass.bin">%assetic.sass.bin%</parameter>
<parameter key="assetic.filter.sass.style">null</parameter>
<parameter key="assetic.filter.sass.compass">null</parameter>
</parameters>
<services>
<service id="assetic.filter.sass" class="%assetic.filter.sass.class%">
<tag name="assetic.filter" alias="sass" />
<argument>%assetic.filter.sass.bin%</argument>
<call method="setStyle"><argument>%assetic.filter.sass.style%</argument></call>
<call method="setCompass"><argument>%assetic.filter.sass.compass%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.scss.class">Assetic\Filter\Sass\ScssFilter</parameter>
<parameter key="assetic.filter.scss.sass">%assetic.sass.bin%</parameter>
<parameter key="assetic.filter.scss.style">null</parameter>
<parameter key="assetic.filter.scss.compass">null</parameter>
</parameters>
<services>
<service id="assetic.filter.scss" class="%assetic.filter.scss.class%">
<tag name="assetic.filter" alias="scss" />
<argument>%assetic.filter.scss.sass%</argument>
<call method="setStyle"><argument>%assetic.filter.scss.style%</argument></call>
<call method="setCompass"><argument>%assetic.filter.scss.compass%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.sprockets.class">Assetic\Filter\SprocketsFilter</parameter>
<parameter key="assetic.filter.sprockets.lib">null</parameter>
<parameter key="assetic.filter.sprockets.ruby">%assetic.ruby.bin%</parameter>
<parameter key="assetic.filter.sprockets.asset_root">%assetic.write_to%</parameter>
<parameter key="assetic.filter.sprockets.include_dirs" type="collection" />
</parameters>
<services>
<service id="assetic.filter.sprockets" class="%assetic.filter.sprockets.class%">
<tag name="assetic.filter" alias="sprockets" />
<argument>%assetic.filter.sprockets.lib%</argument>
<argument>%assetic.filter.sprockets.ruby%</argument>
<call method="setAssetRoot"><argument>%assetic.filter.sprockets.asset_root%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.stylus.class">Assetic\Filter\StylusFilter</parameter>
<parameter key="assetic.filter.stylus.node">%assetic.node.bin%</parameter>
<parameter key="assetic.filter.stylus.node_paths">%assetic.node.paths%</parameter>
<parameter key="assetic.filter.stylus.compress">null</parameter>
</parameters>
<services>
<service id="assetic.filter.stylus" class="%assetic.filter.stylus.class%">
<tag name="assetic.filter" alias="stylus" />
<argument>%assetic.filter.stylus.node%</argument>
<argument>%assetic.filter.stylus.node_paths%</argument>
<call method="setCompress"><argument>%assetic.filter.stylus.compress%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.uglifyjs.class">Assetic\Filter\UglifyJsFilter</parameter>
<parameter key="assetic.filter.uglifyjs.bin">/usr/bin/uglifyjs</parameter>
<parameter key="assetic.filter.uglifyjs.node">%assetic.node.bin%</parameter>
<parameter key="assetic.filter.uglifyjs.beautify">false</parameter>
<parameter key="assetic.filter.uglifyjs.no_copyright">false</parameter>
<parameter key="assetic.filter.uglifyjs.unsafe">false</parameter>
</parameters>
<services>
<service id="assetic.filter.uglifyjs" class="%assetic.filter.uglifyjs.class%">
<tag name="assetic.filter" alias="uglifyjs" />
<argument>%assetic.filter.uglifyjs.bin%</argument>
<argument>%assetic.filter.uglifyjs.node%</argument>
<call method="setBeautify">
<argument>%assetic.filter.uglifyjs.beautify%</argument>
</call>
<call method="setNoCopyright">
<argument>%assetic.filter.uglifyjs.no_copyright%</argument>
</call>
<call method="setUnsafe">
<argument>%assetic.filter.uglifyjs.unsafe%</argument>
</call>
</service>
</services>
</container>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.yui_css.class">Assetic\Filter\Yui\CssCompressorFilter</parameter>
<parameter key="assetic.filter.yui_css.java">%assetic.java.bin%</parameter>
<parameter key="assetic.filter.yui_css.jar" />
<parameter key="assetic.filter.yui_css.charset">%kernel.charset%</parameter>
</parameters>
<services>
<service id="assetic.filter.yui_css" class="%assetic.filter.yui_css.class%">
<tag name="assetic.filter" alias="yui_css" />
<argument>%assetic.filter.yui_css.jar%</argument>
<argument>%assetic.filter.yui_css.java%</argument>
<call method="setCharset"><argument>%assetic.filter.yui_css.charset%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.filter.yui_js.class">Assetic\Filter\Yui\JsCompressorFilter</parameter>
<parameter key="assetic.filter.yui_js.java">%assetic.java.bin%</parameter>
<parameter key="assetic.filter.yui_js.jar" />
<parameter key="assetic.filter.yui_js.charset">%kernel.charset%</parameter>
<parameter key="assetic.filter.yui_js.nomunge">null</parameter>
<parameter key="assetic.filter.yui_js.preserve_semi">null</parameter>
<parameter key="assetic.filter.yui_js.disable_optimizations">null</parameter>
</parameters>
<services>
<service id="assetic.filter.yui_js" class="%assetic.filter.yui_js.class%">
<tag name="assetic.filter" alias="yui_js" />
<argument>%assetic.filter.yui_js.jar%</argument>
<argument>%assetic.filter.yui_js.java%</argument>
<call method="setCharset"><argument>%assetic.filter.yui_js.charset%</argument></call>
<call method="setNomunge"><argument>%assetic.filter.yui_js.nomunge%</argument></call>
<call method="setPreserveSemi"><argument>%assetic.filter.yui_js.preserve_semi%</argument></call>
<call method="setDisableOptimizations"><argument>%assetic.filter.yui_js.disable_optimizations%</argument></call>
</service>
</services>
</container>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://symfony.com/schema/dic/assetic"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://symfony.com/schema/dic/assetic"
elementFormDefault="qualified">
<xsd:element name="config" type="config" />
<xsd:complexType name="config">
<xsd:sequence>
<xsd:element name="bundle" type="bundle" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="filter" type="filter" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="twig" type="twig" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="asset" type="asset" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="debug" type="xsd:string" />
<xsd:attribute name="use-controller" type="xsd:string" />
<xsd:attribute name="read-from" type="xsd:string" />
<xsd:attribute name="write-to" type="xsd:string" />
<xsd:attribute name="dump-on-warmup" type="xsd:string" />
<xsd:attribute name="java" type="xsd:string" />
<xsd:attribute name="node" type="xsd:string" />
<xsd:attribute name="sass" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="bundle">
<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" />
<xsd:anyAttribute namespace="##any" processContents="lax" />
</xsd:complexType>
<xsd:complexType name="twig">
<xsd:sequence>
<xsd:element name="function" type="twig_function" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="twig_function">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:anyAttribute namespace="##any" processContents="lax" />
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="assetic.helper.dynamic.class">Symfony\Bundle\AsseticBundle\Templating\DynamicAsseticHelper</parameter>
<parameter key="assetic.helper.static.class">Symfony\Bundle\AsseticBundle\Templating\StaticAsseticHelper</parameter>
<parameter key="assetic.php_formula_loader.class">Symfony\Bundle\AsseticBundle\Factory\Loader\AsseticHelperFormulaLoader</parameter>
</parameters>
<services>
<service id="assetic.helper.dynamic" class="%assetic.helper.dynamic.class%">
<tag name="assetic.templating.php" />
<argument type="service" id="templating.helper.router" />
<argument type="service" id="assetic.asset_factory" />
</service>
<service id="assetic.helper.static" class="%assetic.helper.static.class%" scope="request">
<tag name="assetic.templating.php" />
<argument type="service" id="templating.helper.assets" />
<argument type="service" id="assetic.asset_factory" />
</service>
<service id="assetic.php_formula_loader" class="%assetic.cached_formula_loader.class%" public="false">
<tag name="assetic.formula_loader" alias="php" />
<tag name="assetic.templating.php" />
<argument type="service" id="assetic.php_formula_loader.real" />
<argument type="service" id="assetic.config_cache" />
<argument>%kernel.debug%</argument>
</service>
<service id="assetic.php_formula_loader.real" class="%assetic.php_formula_loader.class%" public="false">
<tag name="assetic.templating.php" />
<argument type="service" id="assetic.asset_factory" />
</service>
</services>
</container>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<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>
<services>
<service id="assetic.twig_extension" class="%assetic.twig_extension.class%" public="false">
<tag name="twig.extension" />
<tag name="assetic.templating.twig" />
<argument type="service" id="assetic.asset_factory" />
<argument type="service" id="templating.name_parser" />
<argument>%assetic.use_controller%</argument>
<argument>%assetic.twig_extension.functions%</argument>
<argument>%assetic.bundles%</argument>
<argument type="service" id="assetic.value_supplier" on-invalid="null" />
</service>
<service id="assetic.twig_formula_loader" class="%assetic.cached_formula_loader.class%" public="false">
<tag name="assetic.formula_loader" alias="twig" />
<tag name="assetic.templating.twig" />
<argument type="service" id="assetic.twig_formula_loader.real" />
<argument type="service" id="assetic.config_cache" />
<argument>%kernel.debug%</argument>
</service>
<service id="assetic.twig_formula_loader.real" class="%assetic.twig_formula_loader.class%" public="false">
<tag name="assetic.templating.twig" />
<argument type="service" id="twig" />
</service>
</services>
</container>

View File

@@ -0,0 +1,122 @@
<?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\Routing;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\LazyAssetManager;
use Symfony\Bundle\AsseticBundle\Config\AsseticResource;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Loads routes for all assets.
*
* Assets should only be served through the routing system for ease-of-use
* during development.
*
* For example, add the following to your application's routing_dev.yml:
*
* _assetic:
* resource: .
* type: assetic
*
* In a production environment you should use the `assetic:dump` command to
* create static asset files.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticLoader extends Loader
{
protected $am;
public function __construct(LazyAssetManager $am)
{
$this->am = $am;
}
public function load($routingResource, $type = null)
{
$routes = new RouteCollection();
// resources
foreach ($this->am->getResources() as $resources) {
if (!$resources instanceof \Traversable) {
$resources = array($resources);
}
foreach ($resources as $resource) {
$routes->addResource(new AsseticResource($resource));
}
}
// routes
foreach ($this->am->getNames() as $name) {
$asset = $this->am->get($name);
$formula = $this->am->getFormula($name);
$this->loadRouteForAsset($routes, $asset, $name);
$debug = isset($formula[2]['debug']) ? $formula[2]['debug'] : $this->am->isDebug();
$combine = isset($formula[2]['combine']) ? $formula[2]['combine'] : !$debug;
// add a route for each "leaf" in debug mode
if (!$combine) {
$i = 0;
foreach ($asset as $leaf) {
$this->loadRouteForAsset($routes, $leaf, $name, $i++);
}
}
}
return $routes;
}
/**
* Loads a route to serve an supplied asset.
*
* The fake front controller that {@link UseControllerWorker} adds to the
* target URL will be removed before set as a route pattern.
*
* @param RouteCollection $routes The route collection
* @param AssetInterface $asset The asset
* @param string $name The name to use
* @param integer $pos The leaf index
*/
private function loadRouteForAsset(RouteCollection $routes, AssetInterface $asset, $name, $pos = null)
{
$defaults = array(
'_controller' => 'assetic.controller:render',
'name' => $name,
'pos' => $pos,
);
// remove the fake front controller
$pattern = str_replace('_controller/', '', $asset->getTargetPath());
if ($format = pathinfo($pattern, PATHINFO_EXTENSION)) {
$defaults['_format'] = $format;
}
$route = '_assetic_'.$name;
if (null !== $pos) {
$route .= '_'.$pos;
}
$routes->add($route, new Route($pattern, $defaults));
}
public function supports($resource, $type = null)
{
return 'assetic' == $type;
}
}

View File

@@ -0,0 +1,157 @@
<?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\Templating;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\AssetFactory;
use Assetic\Util\TraversableString;
use Symfony\Component\Templating\Helper\Helper;
/**
* The "assetic" templating helper.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
abstract class AsseticHelper extends Helper
{
protected $factory;
/**
* Constructor.
*
* @param AssetFactory $factory The asset factory
*/
public function __construct(AssetFactory $factory)
{
$this->factory = $factory;
}
/**
* Returns an array of javascript urls.
*/
public function javascripts($inputs = array(), $filters = array(), array $options = array())
{
if (!isset($options['output'])) {
$options['output'] = 'js/*.js';
}
return $this->getAssetUrls($inputs, $filters, $options);
}
/**
* Returns an array of stylesheet urls.
*/
public function stylesheets($inputs = array(), $filters = array(), array $options = array())
{
if (!isset($options['output'])) {
$options['output'] = 'css/*.css';
}
return $this->getAssetUrls($inputs, $filters, $options);
}
/**
* Returns an array of one image url.
*/
public function image($inputs = array(), $filters = array(), array $options = array())
{
if (!isset($options['output'])) {
$options['output'] = 'images/*';
}
$options['single'] = true;
return $this->getAssetUrls($inputs, $filters, $options);
}
/**
* Gets the URLs for the configured asset.
*
* Usage looks something like this:
*
* <?php foreach ($view['assetic']->assets('@jquery, js/src/core/*', '?yui_js') as $url): ?>
* <script src="<?php echo $url ?>" type="text/javascript"></script>
* <?php endforeach; ?>
*
* When in debug mode, the helper returns an array of one or more URLs.
* When not in debug mode it returns an array of one URL.
*
* @param array|string $inputs An array or comma-separated list of input strings
* @param array|string $filters An array or comma-separated list of filter names
* @param array $options An array of options
*
* @return array An array of URLs for the asset
*/
private function getAssetUrls($inputs = array(), $filters = array(), array $options = array())
{
$explode = function($value)
{
return array_map('trim', explode(',', $value));
};
if (!is_array($inputs)) {
$inputs = $explode($inputs);
}
if (!is_array($filters)) {
$filters = $explode($filters);
}
if (!isset($options['debug'])) {
$options['debug'] = $this->factory->isDebug();
}
if (!isset($options['combine'])) {
$options['combine'] = !$options['debug'];
}
if (isset($options['single']) && $options['single'] && 1 < count($inputs)) {
$inputs = array_slice($inputs, -1);
}
if (!isset($options['name'])) {
$options['name'] = $this->factory->generateAssetName($inputs, $filters, $options);
}
$asset = $this->factory->createAsset($inputs, $filters, $options);
$one = $this->getAssetUrl($asset, $options);
$many = array();
if ($options['combine']) {
$many[] = $one;
} else {
$i = 0;
foreach ($asset as $leaf) {
$many[] = $this->getAssetUrl($leaf, array_replace($options, array(
'name' => $options['name'].'_'.$i++,
)));
}
}
return new TraversableString($one, $many);
}
/**
* Returns an URL for the supplied asset.
*
* @param AssetInterface $asset An asset
* @param array $options An array of options
*
* @return string An echo-ready URL
*/
abstract protected function getAssetUrl(AssetInterface $asset, $options = array());
public function getName()
{
return 'assetic';
}
}

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\Templating;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\AssetFactory;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\RouterHelper;
/**
* The dynamic "assetic" templating helper.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class DynamicAsseticHelper extends AsseticHelper
{
private $routerHelper;
/**
* Constructor.
*
* @param RouterHelper $routerHelper The router helper
* @param AssetFactory $factory The asset factory
*/
public function __construct(RouterHelper $routerHelper, AssetFactory $factory)
{
$this->routerHelper = $routerHelper;
parent::__construct($factory);
}
protected function getAssetUrl(AssetInterface $asset, $options = array())
{
return $this->routerHelper->generate('_assetic_'.$options['name']);
}
}

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\Templating;
use Assetic\Asset\AssetInterface;
use Assetic\Factory\AssetFactory;
use Symfony\Component\Templating\Helper\CoreAssetsHelper;
/**
* The static "assetic" templating helper.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class StaticAsseticHelper extends AsseticHelper
{
private $assetsHelper;
/**
* Constructor.
*
* @param CoreAssetsHelper $assetsHelper The assets helper
* @param AssetFactory $factory The asset factory
*/
public function __construct(CoreAssetsHelper $assetsHelper, AssetFactory $factory)
{
$this->assetsHelper = $assetsHelper;
parent::__construct($factory);
}
protected function getAssetUrl(AssetInterface $asset, $options = array())
{
return $this->assetsHelper->getUrl($asset->getTargetPath(), isset($options['package']) ? $options['package'] : null);
}
}

View File

@@ -0,0 +1,51 @@
<?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\Tests\CacheWarmer;
use Symfony\Bundle\AsseticBundle\CacheWarmer\AssetManagerCacheWarmer;
class AssetManagerCacheWarmerTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
}
public function testWarmUp()
{
$am = $this
->getMockBuilder('Assetic\\Factory\\LazyAssetManager')
->disableOriginalConstructor()
->getMock()
;
$am->expects($this->once())->method('load');
$container = $this
->getMockBuilder('Symfony\\Component\\DependencyInjection\\Container')
->setConstructorArgs(array())
->getMock()
;
$container
->expects($this->once())
->method('get')
->with('assetic.asset_manager')
->will($this->returnValue($am))
;
$warmer = new AssetManagerCacheWarmer($container);
$warmer->warmUp('/path/to/cache');
}
}

View File

@@ -0,0 +1,202 @@
<?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\Tests\Command;
use Symfony\Bundle\AsseticBundle\Command\DumpCommand;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\NullOutput;
class DumpCommandTest extends \PHPUnit_Framework_TestCase
{
private $writeTo;
private $application;
private $definition;
private $kernel;
private $container;
private $am;
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
$this->writeTo = sys_get_temp_dir().'/assetic_dump';
$this->application = $this->getMockBuilder('Symfony\\Bundle\\FrameworkBundle\\Console\\Application')
->disableOriginalConstructor()
->getMock();
$this->definition = $this->getMockBuilder('Symfony\\Component\\Console\\Input\\InputDefinition')
->disableOriginalConstructor()
->getMock();
$this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface');
$this->helperSet = $this->getMock('Symfony\\Component\\Console\\Helper\\HelperSet');
$this->container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface');
$this->am = $this->getMockBuilder('Assetic\\Factory\\LazyAssetManager')
->disableOriginalConstructor()
->getMock();
$this->application->expects($this->any())
->method('getDefinition')
->will($this->returnValue($this->definition));
$this->definition->expects($this->any())
->method('getArguments')
->will($this->returnValue(array()));
$this->definition->expects($this->any())
->method('getOptions')
->will($this->returnValue(array(
new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'),
new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'),
new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'),
)));
$this->application->expects($this->any())
->method('getKernel')
->will($this->returnValue($this->kernel));
$this->application->expects($this->once())
->method('getHelperSet')
->will($this->returnValue($this->helperSet));
$this->kernel->expects($this->any())
->method('getContainer')
->will($this->returnValue($this->container));
$writeTo = $this->writeTo;
$this->container->expects($this->any())
->method('getParameter')
->will($this->returnCallback(function($p) use($writeTo) {
if ('assetic.write_to' === $p) {
return $writeTo;
} else if ('assetic.variables' === $p) {
return array();
}
throw new \RuntimeException(sprintf('Unknown parameter "%s".', $p));
}));
$this->container->expects($this->once())
->method('get')
->with('assetic.asset_manager')
->will($this->returnValue($this->am));
$this->command = new DumpCommand();
$this->command->setApplication($this->application);
}
protected function tearDown()
{
if (is_dir($this->writeTo)) {
array_map('unlink', glob($this->writeTo.'/*'));
rmdir($this->writeTo);
}
}
public function testEmptyAssetManager()
{
$this->am->expects($this->once())
->method('getNames')
->will($this->returnValue(array()));
$this->command->run(new ArrayInput(array()), new NullOutput());
}
public function testDumpOne()
{
$asset = $this->getMock('Assetic\\Asset\\AssetInterface');
$this->am->expects($this->once())
->method('getNames')
->will($this->returnValue(array('test_asset')));
$this->am->expects($this->once())
->method('get')
->with('test_asset')
->will($this->returnValue($asset));
$this->am->expects($this->once())
->method('getFormula')
->with('test_asset')
->will($this->returnValue(array()));
$this->am->expects($this->once())
->method('isDebug')
->will($this->returnValue(false));
$asset->expects($this->once())
->method('getTargetPath')
->will($this->returnValue('test_asset.css'));
$asset->expects($this->once())
->method('dump')
->will($this->returnValue('/* test_asset */'));
$asset->expects($this->any())
->method('getVars')
->will($this->returnValue(array()));
$asset->expects($this->any())
->method('getValues')
->will($this->returnValue(array()));
$this->command->run(new ArrayInput(array()), new NullOutput());
$this->assertFileExists($this->writeTo.'/test_asset.css');
$this->assertEquals('/* test_asset */', file_get_contents($this->writeTo.'/test_asset.css'));
}
public function testDumpDebug()
{
$asset = $this->getMock('Assetic\\Asset\\AssetCollection');
$leaf = $this->getMock('Assetic\\Asset\\AssetInterface');
$this->am->expects($this->once())
->method('getNames')
->will($this->returnValue(array('test_asset')));
$this->am->expects($this->once())
->method('get')
->with('test_asset')
->will($this->returnValue($asset));
$this->am->expects($this->once())
->method('getFormula')
->with('test_asset')
->will($this->returnValue(array()));
$this->am->expects($this->once())
->method('isDebug')
->will($this->returnValue(true));
$asset->expects($this->once())
->method('getTargetPath')
->will($this->returnValue('test_asset.css'));
$asset->expects($this->once())
->method('dump')
->will($this->returnValue('/* test_asset */'));
$asset->expects($this->once())
->method('getIterator')
->will($this->returnValue(new \ArrayIterator(array($leaf))));
$asset->expects($this->any())
->method('getVars')
->will($this->returnValue(array()));
$asset->expects($this->any())
->method('getValues')
->will($this->returnValue(array()));
$leaf->expects($this->once())
->method('getTargetPath')
->will($this->returnValue('test_leaf.css'));
$leaf->expects($this->once())
->method('dump')
->will($this->returnValue('/* test_leaf */'));
$leaf->expects($this->any())
->method('getVars')
->will($this->returnValue(array()));
$leaf->expects($this->any())
->method('getValues')
->will($this->returnValue(array()));
$this->command->run(new ArrayInput(array()), new NullOutput());
$this->assertFileExists($this->writeTo.'/test_asset.css');
$this->assertFileExists($this->writeTo.'/test_leaf.css');
$this->assertEquals('/* test_asset */', file_get_contents($this->writeTo.'/test_asset.css'));
$this->assertEquals('/* test_leaf */', file_get_contents($this->writeTo.'/test_leaf.css'));
}
}

View File

@@ -0,0 +1,167 @@
<?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\Tests\Controller;
use Symfony\Bundle\AsseticBundle\Controller\AsseticController;
class AsseticControllerTest extends \PHPUnit_Framework_TestCase
{
protected $request;
protected $headers;
protected $am;
protected $cache;
protected $controller;
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
$this->request = $this->getMock('Symfony\\Component\\HttpFoundation\\Request');
$this->headers = $this->getMock('Symfony\\Component\\HttpFoundation\\ParameterBag');
$this->request->headers = $this->headers;
$this->am = $this->getMockBuilder('Assetic\\Factory\\LazyAssetManager')
->disableOriginalConstructor()
->getMock();
$this->cache = $this->getMock('Assetic\\Cache\\CacheInterface');
$this->controller = new AsseticController($this->request, $this->am, $this->cache);
}
public function testRenderNotFound()
{
$this->setExpectedException('Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException');
$name = 'foo';
$this->am->expects($this->once())
->method('has')
->with($name)
->will($this->returnValue(false));
$this->controller->render($name);
}
public function testRenderLastModifiedFresh()
{
$asset = $this->getMock('Assetic\\Asset\\AssetInterface');
$name = 'foo';
$lastModified = strtotime('2010-10-10 10:10:10');
$ifModifiedSince = gmdate('D, d M Y H:i:s', $lastModified).' GMT';
$asset->expects($this->any())->method('getFilters')->will($this->returnValue(array()));
$this->am->expects($this->once())->method('has')->with($name)->will($this->returnValue(true));
$this->am->expects($this->once())->method('get')->with($name)->will($this->returnValue($asset));
$asset->expects($this->once())->method('getLastModified')->will($this->returnValue($lastModified));
$this->headers->expects($this->once())->method('get')->with('If-Modified-Since')->will($this->returnValue($ifModifiedSince));
$asset->expects($this->never())
->method('dump');
$response = $this->controller->render($name);
$this->assertEquals(304, $response->getStatusCode(), '->render() sends a Not Modified response when If-Modified-Since is fresh');
}
public function testRenderLastModifiedStale()
{
$asset = $this->getMock('Assetic\\Asset\\AssetInterface');
$name = 'foo';
$content = '==ASSET_CONTENT==';
$lastModified = strtotime('2010-10-10 10:10:10');
$ifModifiedSince = gmdate('D, d M Y H:i:s', $lastModified - 300).' GMT';
$asset->expects($this->any())->method('getFilters')->will($this->returnValue(array()));
$this->am->expects($this->once())->method('has')->with($name)->will($this->returnValue(true));
$this->am->expects($this->once())->method('get')->with($name)->will($this->returnValue($asset));
$asset->expects($this->exactly(2))->method('getLastModified')->will($this->returnValue($lastModified));
$this->headers->expects($this->once())->method('get')->with('If-Modified-Since')->will($this->returnValue($ifModifiedSince));
$this->cache->expects($this->once())
->method('has')
->with($this->isType('string'))
->will($this->returnValue(false));
$asset->expects($this->once())
->method('dump')
->will($this->returnValue($content));
$response = $this->controller->render($name);
$this->assertEquals(200, $response->getStatusCode(), '->render() sends an OK response when If-Modified-Since is stale');
$this->assertEquals($content, $response->getContent(), '->render() sends the dumped asset as the response content');
}
public function testRenderETagFresh()
{
$asset = $this->getMock('Assetic\\Asset\\AssetInterface');
$name = 'foo';
$formula = array(array('js/core.js'), array(), array(''));
$etag = md5(serialize($formula + array('last_modified' => null)));
$asset->expects($this->any())->method('getFilters')->will($this->returnValue(array()));
$this->am->expects($this->once())->method('has')->with($name)->will($this->returnValue(true));
$this->am->expects($this->once())->method('get')->with($name)->will($this->returnValue($asset));
$this->am->expects($this->once())
->method('hasFormula')
->with($name)
->will($this->returnValue(true));
$this->am->expects($this->once())
->method('getFormula')
->with($name)
->will($this->returnValue($formula));
$this->request->expects($this->once())
->method('getETags')
->will($this->returnValue(array('"'.$etag.'"')));
$asset->expects($this->never())
->method('dump');
$response = $this->controller->render($name);
$this->assertEquals(304, $response->getStatusCode(), '->render() sends a Not Modified response when If-None-Match is fresh');
}
public function testRenderETagStale()
{
$asset = $this->getMock('Assetic\\Asset\\AssetInterface');
$name = 'foo';
$content = '==ASSET_CONTENT==';
$formula = array(array('js/core.js'), array(), array(''));
$etag = md5(serialize($formula + array('last_modified' => null)));
$asset->expects($this->any())->method('getFilters')->will($this->returnValue(array()));
$this->am->expects($this->once())->method('has')->with($name)->will($this->returnValue(true));
$this->am->expects($this->once())->method('get')->with($name)->will($this->returnValue($asset));
$this->am->expects($this->once())
->method('hasFormula')
->with($name)
->will($this->returnValue(true));
$this->am->expects($this->once())
->method('getFormula')
->with($name)
->will($this->returnValue($formula));
$this->request->expects($this->once())
->method('getETags')
->will($this->returnValue(array('"123"')));
$asset->expects($this->once())
->method('dump')
->will($this->returnValue($content));
$response = $this->controller->render($name);
$this->assertEquals(200, $response->getStatusCode(), '->render() sends an OK response when If-None-Match is stale');
$this->assertEquals($content, $response->getContent(), '->render() sends the dumped asset as the response content');
}
}

View File

@@ -0,0 +1,215 @@
<?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\Tests\DependencyInjection;
use Symfony\Bundle\AsseticBundle\DependencyInjection\AsseticExtension;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\CheckYuiFilterPass;
use Symfony\Bundle\AsseticBundle\DependencyInjection\Compiler\CheckClosureFilterPass;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Scope;
use Symfony\Component\HttpFoundation\Request;
class AsseticExtensionTest extends \PHPUnit_Framework_TestCase
{
private $kernel;
private $container;
static public function assertSaneContainer(Container $container, $message = '')
{
$errors = array();
foreach ($container->getServiceIds() as $id) {
try {
$container->get($id);
} catch (\Exception $e) {
$errors[$id] = $e->getMessage();
}
}
self::assertEquals(array(), $errors, $message);
}
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
$this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface');
$this->container = new ContainerBuilder();
$this->container->addScope(new Scope('request'));
$this->container->register('request', 'Symfony\\Component\\HttpFoundation\\Request')->setScope('request');
$this->container->register('templating.helper.assets', $this->getMockClass('Symfony\\Component\\Templating\\Helper\\AssetsHelper'));
$this->container->register('templating.helper.router', $this->getMockClass('Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\RouterHelper'))
->addArgument(new Definition($this->getMockClass('Symfony\\Component\\Routing\\RouterInterface')));
$this->container->register('twig', 'Twig_Environment');
$this->container->setParameter('kernel.bundles', array());
$this->container->setParameter('kernel.cache_dir', __DIR__);
$this->container->setParameter('kernel.debug', false);
$this->container->setParameter('kernel.root_dir', __DIR__);
$this->container->setParameter('kernel.charset', 'UTF-8');
$this->container->set('kernel', $this->kernel);
}
/**
* @dataProvider getDebugModes
*/
public function testDefaultConfig($debug)
{
$this->container->setParameter('kernel.debug', $debug);
$extension = new AsseticExtension();
$extension->load(array(array()), $this->container);
$this->assertFalse($this->container->has('assetic.filter.yui_css'), '->load() does not load the yui_css filter when a yui value is not provided');
$this->assertFalse($this->container->has('assetic.filter.yui_js'), '->load() does not load the yui_js filter when a yui value is not provided');
$this->assertSaneContainer($this->getDumpedContainer());
}
public function getDebugModes()
{
return array(
array(true),
array(false),
);
}
/**
* @dataProvider getFilterNames
*/
public function testFilterConfigs($name, $config = array())
{
$extension = new AsseticExtension();
$extension->load(array(array('filters' => array($name => $config))), $this->container);
$this->assertSaneContainer($this->getDumpedContainer());
}
public function getFilterNames()
{
return array(
array('closure', array('jar' => '/path/to/closure.jar')),
array('coffee'),
array('compass'),
array('cssembed', array('jar' => '/path/to/cssembed.jar')),
array('cssimport'),
array('cssrewrite'),
array('jpegoptim'),
array('jpegtran'),
array('less'),
array('lessphp'),
array('optipng'),
array('packager'),
array('pngout'),
array('sass'),
array('scss'),
array('sprockets', array('include_dirs' => array('foo'))),
array('stylus'),
array('yui_css', array('jar' => '/path/to/yuicompressor.jar')),
array('yui_js', array('jar' => '/path/to/yuicompressor.jar')),
);
}
/**
* @dataProvider getUseControllerKeys
*/
public function testUseController($bool, $includes, $omits)
{
$extension = new AsseticExtension();
$extension->load(array(array('use_controller' => $bool)), $this->container);
foreach ($includes as $id) {
$this->assertTrue($this->container->has($id), '"'.$id.'" is registered when use_controller is '.$bool);
}
foreach ($omits as $id) {
$this->assertFalse($this->container->has($id), '"'.$id.'" is not registered when use_controller is '.$bool);
}
$this->assertSaneContainer($this->getDumpedContainer());
}
public function getUseControllerKeys()
{
return array(
array(true, array('assetic.routing_loader', 'assetic.controller'), array()),
array(false, array(), array('assetic.routing_loader', 'assetic.controller')),
);
}
/**
* @dataProvider getClosureJarAndExpected
*/
public function testClosureCompilerPass($jar, $expected)
{
$this->container->addCompilerPass(new CheckClosureFilterPass());
$extension = new AsseticExtension();
$extension->load(array(array(
'filters' => array(
'closure' => array('jar' => $jar),
),
)), $this->container);
$container = $this->getDumpedContainer();
$this->assertSaneContainer($container);
$this->assertTrue($this->container->getDefinition($expected)->hasTag('assetic.filter'));
$this->assertNotEmpty($container->getParameter('assetic.filter.closure.java'));
}
public function getClosureJarAndExpected()
{
return array(
array(null, 'assetic.filter.closure.api'),
array('/path/to/closure.jar', 'assetic.filter.closure.jar'),
);
}
public function testInvalidYuiConfig()
{
$this->setExpectedException('RuntimeException', 'assetic.filters.yui_js');
$this->container->addCompilerPass(new CheckYuiFilterPass());
$extension = new AsseticExtension();
$extension->load(array(array(
'filters' => array(
'yui_js' => array(),
),
)), $this->container);
$this->getDumpedContainer();
}
private function getDumpedContainer()
{
static $i = 0;
$class = 'AsseticExtensionTestContainer'.$i++;
$this->container->compile();
$dumper = new PhpDumper($this->container);
eval('?>'.$dumper->dump(array('class' => $class)));
$container = new $class();
$container->enterScope('request');
$container->set('request', Request::create('/'));
$container->set('kernel', $this->kernel);
return $container;
}
}

View File

@@ -0,0 +1,97 @@
<?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\Tests\Factory;
use Symfony\Bundle\AsseticBundle\Factory\AssetFactory;
class AssetFactoryTest extends \PHPUnit_Framework_TestCase
{
protected $kernel;
protected $factory;
protected $container;
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
$this->kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface');
$this->container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface');
$this->parameterBag = $this->getMock('Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBagInterface');
$this->factory = new AssetFactory($this->kernel, $this->container, $this->parameterBag, '/path/to/web');
}
public function testBundleNotation()
{
$input = '@MyBundle/Resources/css/main.css';
$bundle = $this->getMock('Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface');
$this->parameterBag->expects($this->once())
->method('resolveValue')
->will($this->returnCallback(function($v) { return $v; }));
$this->kernel->expects($this->once())
->method('getBundle')
->with('MyBundle')
->will($this->returnValue($bundle));
$this->kernel->expects($this->once())
->method('locateResource')
->with($input)
->will($this->returnValue('/path/to/MyBundle/Resources/css/main.css'));
$bundle->expects($this->once())
->method('getPath')
->will($this->returnValue('/path/to/MyBundle'));
$coll = $this->factory->createAsset($input)->all();
$asset = $coll[0];
$this->assertEquals('/path/to/MyBundle', $asset->getSourceRoot(), '->createAsset() sets the asset root');
$this->assertEquals('Resources/css/main.css', $asset->getSourcePath(), '->createAsset() sets the asset path');
}
/**
* @dataProvider getGlobs
*/
public function testBundleGlobNotation($input)
{
$bundle = $this->getMock('Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface');
$this->parameterBag->expects($this->once())
->method('resolveValue')
->will($this->returnCallback(function($v) { return $v; }));
$this->kernel->expects($this->once())
->method('getBundle')
->with('MyBundle')
->will($this->returnValue($bundle));
$this->kernel->expects($this->once())
->method('locateResource')
->with('@MyBundle/Resources/css/')
->will($this->returnValue('/path/to/MyBundle/Resources/css/'));
$bundle->expects($this->once())
->method('getPath')
->will($this->returnValue('/path/to/MyBundle'));
$coll = $this->factory->createAsset($input)->all();
$asset = $coll[0];
$this->assertEquals('/path/to/MyBundle', $asset->getSourceRoot(), '->createAsset() sets the asset root');
$this->assertNull($asset->getSourcePath(), '->createAsset() sets the asset path to null');
}
public function getGlobs()
{
return array(
array('@MyBundle/Resources/css/*'),
array('@MyBundle/Resources/css/*/*.css'),
);
}
}

View File

@@ -0,0 +1,63 @@
<?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\Tests\Factory\Resource;
use Symfony\Bundle\AsseticBundle\Factory\Resource\CoalescingDirectoryResource;
class CoalescingDirectoryResourceTest extends \PHPUnit_Framework_TestCase
{
public function testFiltering()
{
$dir1 = $this->getMock('Assetic\\Factory\\Resource\\IteratorResourceInterface');
$file1a = $this->getMock('Assetic\\Factory\\Resource\\ResourceInterface');
$file1b = $this->getMock('Assetic\\Factory\\Resource\\ResourceInterface');
$dir2 = $this->getMock('Assetic\\Factory\\Resource\\IteratorResourceInterface');
$file2a = $this->getMock('Assetic\\Factory\\Resource\\ResourceInterface');
$file2c = $this->getMock('Assetic\\Factory\\Resource\\ResourceInterface');
$dir1->expects($this->any())
->method('getIterator')
->will($this->returnValue(new \ArrayIterator(array($file1a, $file1b))));
$file1a->expects($this->any())
->method('__toString')
->will($this->returnValue('FooBundle:Foo:file1.foo.bar'));
$file1b->expects($this->any())
->method('__toString')
->will($this->returnValue('FooBundle:Foo:file2.foo.bar'));
$dir2->expects($this->any())
->method('getIterator')
->will($this->returnValue(new \ArrayIterator(array($file2a, $file2c))));
$file2a->expects($this->any())
->method('__toString')
->will($this->returnValue('BarBundle:Foo:file1.foo.bar'));
$file2c->expects($this->any())
->method('__toString')
->will($this->returnValue('BarBundle:Foo:file3.foo.bar'));
$resource = new CoalescingDirectoryResource(array($dir1, $dir2));
$actual = array();
foreach ($resource as $file) {
$actual[] = (string) $file;
}
$expected = array(
'FooBundle:Foo:file1.foo.bar',
'FooBundle:Foo:file2.foo.bar',
'BarBundle:Foo:file3.foo.bar',
);
$this->assertEquals($expected, $actual);
}
}

View File

@@ -0,0 +1,31 @@
<?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\Tests\Factory\Resource;
use Symfony\Bundle\AsseticBundle\Factory\Resource\FileResource;
class FileResourceTest extends \PHPUnit_Framework_TestCase
{
private $loader;
protected function setUp()
{
$this->loader = $this->getMock('Symfony\\Component\\Templating\\Loader\\LoaderInterface');
}
public function testCastAsString()
{
$baseDir = '/path/to/MyBundle/Resources/views/';
$resource = new FileResource($this->loader, 'MyBundle', $baseDir, $baseDir.'Section/template.html.twig');
$this->assertEquals('MyBundle:Section:template.html.twig', (string) $resource);
}
}

View File

@@ -0,0 +1,59 @@
<?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\Tests;
use Symfony\Bundle\AsseticBundle\FilterManager;
class FilterManagerTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
}
public function testGet()
{
$container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface');
$filter = $this->getMock('Assetic\\Filter\\FilterInterface');
$container->expects($this->exactly(2))
->method('get')
->with('assetic.filter.bar')
->will($this->returnValue($filter));
$fm = new FilterManager($container, array('foo' => 'assetic.filter.bar'));
$this->assertSame($filter, $fm->get('foo'), '->get() loads the filter from the container');
$this->assertSame($filter, $fm->get('foo'), '->get() loads the filter from the container');
}
public function testHas()
{
$container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface');
$fm = new FilterManager($container, array('foo' => 'assetic.filter.bar'));
$this->assertTrue($fm->has('foo'), '->has() returns true for lazily mapped filters');
}
public function testGetNames()
{
$container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface');
$filter = $this->getMock('Assetic\\Filter\\FilterInterface');
$fm = new FilterManager($container, array('foo' => 'assetic.filter.bar'));
$fm->set('bar', $filter);
$this->assertEquals(array('foo', 'bar'), $fm->getNames(), '->getNames() returns all lazy and normal filter names');
}
}

View File

@@ -0,0 +1,75 @@
<?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\Tests;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Filesystem\Filesystem;
/**
* @group functional
*/
class FunctionalTest extends \PHPUnit_Framework_TestCase
{
protected $cacheDir;
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
$this->cacheDir = __DIR__.'/Resources/cache';
if (file_exists($this->cacheDir)) {
$filesystem = new Filesystem();
$filesystem->remove($this->cacheDir);
}
mkdir($this->cacheDir, 0777, true);
}
protected function tearDown()
{
$filesystem = new Filesystem();
$filesystem->remove($this->cacheDir);
}
public function testTwigRenderDebug()
{
$kernel = new TestKernel('test', true);
$kernel->boot();
$container = $kernel->getContainer();
$container->enterScope('request');
$container->set('request', new Request());
$content = $container->get('templating')->render('::layout.html.twig');
$crawler = new Crawler($content);
$this->assertEquals(3, count($crawler->filter('link[href$=".css"]')));
$this->assertEquals(2, count($crawler->filter('script[src$=".js"]')));
}
public function testPhpRenderDebug()
{
$kernel = new TestKernel('test', true);
$kernel->boot();
$container = $kernel->getContainer();
$container->enterScope('request');
$container->set('request', new Request());
$content = $container->get('templating')->render('::layout.html.php');
$crawler = new Crawler($content);
$this->assertEquals(3, count($crawler->filter('link[href$=".css"]')));
$this->assertEquals(2, count($crawler->filter('script[src$=".js"]')));
}
}

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title><?php $view['slots']->output('title') ?></title>
<?php $view['slots']->output('stylesheets') ?>
</head>
<body>
<?php $view['slots']->output('_content') ?>
<?php $view['slots']->output('javascripts') ?>
</body>
</html>

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>{% block title '' %}</title>
{% block stylesheets '' %}
</head>
<body>
{% block content '' %}
{% block javascripts '' %}
</body>
</html>

View File

@@ -0,0 +1,17 @@
<?php $view->extend('::base.html.php') ?>
<?php $view['slots']->start('stylesheets') ?>
<?php foreach($view['assetic']->stylesheets('stylesheet1.css, stylesheet2.css, @TestBundle/Resources/css/bundle.css') as $url): ?>
<link href="<?php echo $view->escape($url) ?>" type="text/css" rel="stylesheet" />
<?php endforeach; ?>
<?php $view['slots']->stop() ?>
<?php $view['slots']->start('javascripts') ?>
<?php foreach($view['assetic']->javascripts('javascript1.js, javascript2.js') as $url): ?>
<script src="<?php echo $view->escape($url) ?>"></script>
<?php endforeach; ?>
<?php $view['slots']->stop() ?>
<?php foreach ($view['assetic']->image('logo.png') as $url): ?>
<img src="<?php echo $view->escape($url) ?>">
<?php endforeach; ?>

View File

@@ -0,0 +1,19 @@
{% extends '::base.html.twig' %}
{% block stylesheets %}
{% stylesheets 'stylesheet1.css' 'stylesheet2.css' '@TestBundle/Resources/css/bundle.css' %}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
{% endstylesheets %}
{% endblock %}
{% block javascripts %}
{% javascripts 'javascript1.js' 'javascript2.js' %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock %}
{% block content %}
{% image 'logo.png' %}
<img src="{{ asset_url }}">
{% endimage %}
{% endblock %}

View File

@@ -0,0 +1,40 @@
framework:
charset: UTF-8
secret: xxxxxxxxxx
csrf_protection:
enabled: true
router: { resource: "%kernel.root_dir%/config/routing.yml" }
validation: { enabled: true, enable_annotations: true }
templating: { engines: ['twig', 'php'] }
session:
lifetime: 3600
auto_start: false
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
assetic:
use_controller: true
read_from: "%kernel.root_dir%/web"
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:
apply_to: "\.sass$"
yui_css:
jar: %kernel.root_dir/java/yui-compressor-2.4.6.jar
twig:
functions:
yui_css: { output: css/*.css }

View File

@@ -0,0 +1,3 @@
_assetic:
resource: .
type: assetic

View File

@@ -0,0 +1 @@
// javascript1.js

View File

@@ -0,0 +1 @@
// javascript2.js

View File

@@ -0,0 +1 @@
/* stylesheet1.css */

View File

@@ -0,0 +1 @@
/* stylesheet2.css */

View File

@@ -0,0 +1,56 @@
<?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\Tests\Templating;
use Assetic\Asset\AssetCollection;
use Assetic\Asset\AssetInterface;
use Assetic\Asset\StringAsset;
use Assetic\Factory\AssetFactory;
use Symfony\Bundle\AsseticBundle\Templating\AsseticHelper;
class AsseticHelperTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!class_exists('Assetic\\AssetManager')) {
$this->markTestSkipped('Assetic is not available.');
}
}
/**
* @dataProvider getDebugAndCount
*/
public function testUrls($debug, $count, $message)
{
$helper = new AsseticHelperForTest(new AssetFactory('/foo', $debug), $debug);
$urls = $helper->javascripts(array('js/jquery.js', 'js/jquery.plugin.js'));
$this->assertInstanceOf('Traversable', $urls, '->javascripts() returns an array');
$this->assertEquals($count, count($urls), $message);
}
public function getDebugAndCount()
{
return array(
array(false, 1, '->javascripts() returns one url when not in debug mode'),
array(true, 2, '->javascripts() returns many urls when in debug mode'),
);
}
}
class AsseticHelperForTest extends AsseticHelper
{
protected function getAssetUrl(AssetInterface $asset, $options = array())
{
return $asset->getTargetPath();
}
}

View File

@@ -0,0 +1 @@
/* bundle.css */

View File

@@ -0,0 +1,18 @@
<?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\Tests\TestBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class TestBundle extends Bundle
{
}

View File

@@ -0,0 +1,38 @@
<?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\Tests;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class TestKernel extends Kernel
{
public function getRootDir()
{
return __DIR__.'/Resources';
}
public function registerBundles()
{
return array(
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new \Symfony\Bundle\TwigBundle\TwigBundle(),
new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
new \Symfony\Bundle\AsseticBundle\Tests\TestBundle\TestBundle(),
);
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/Resources/config/config.yml');
}
}

View File

@@ -0,0 +1,17 @@
<?php
require_once $_SERVER['SYMFONY'].'/Symfony/Component/ClassLoader/UniversalClassLoader.php';
$loader = new Symfony\Component\ClassLoader\UniversalClassLoader();
$loader->registerNamespace('Symfony', $_SERVER['SYMFONY']);
$loader->registerNamespace('Assetic', $_SERVER['ASSETIC']);
$loader->registerPrefix('Twig_', $_SERVER['TWIG']);
$loader->register();
spl_autoload_register(function($class)
{
if (0 === strpos($class, 'Symfony\\Bundle\\AsseticBundle\\') &&
file_exists($file = __DIR__.'/../'.implode('/', array_slice(explode('\\', $class), 3)).'.php')) {
require_once $file;
}
});

View File

@@ -0,0 +1,69 @@
<?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\ValueSupplierInterface;
use Assetic\Extension\Twig\AsseticExtension as BaseAsseticExtension;
use Assetic\Factory\AssetFactory;
use Symfony\Component\Templating\TemplateNameParserInterface;
/**
* Assetic extension.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticExtension extends BaseAsseticExtension
{
private $useController;
public function __construct(AssetFactory $factory, TemplateNameParserInterface $templateNameParser, $useController = false, $functions = array(), $enabledBundles = array(), ValueSupplierInterface $valueSupplier = null)
{
parent::__construct($factory, $functions, $valueSupplier);
$this->useController = $useController;
$this->templateNameParser = $templateNameParser;
$this->enabledBundles = $enabledBundles;
}
public function getTokenParsers()
{
return array(
$this->createTokenParser('javascripts', 'js/*.js'),
$this->createTokenParser('stylesheets', 'css/*.css'),
$this->createTokenParser('image', 'images/*', true),
);
}
public function getNodeVisitors()
{
return array(
new AsseticNodeVisitor($this->templateNameParser, $this->enabledBundles),
);
}
public function getGlobals()
{
$globals = parent::getGlobals();
$globals['assetic']['use_controller'] = $this->useController;
return $globals;
}
private function createTokenParser($tag, $output, $single = false)
{
$tokenParser = new AsseticTokenParser($this->factory, $tag, $output, $single, array('package'));
$tokenParser->setTemplateNameParser($this->templateNameParser);
$tokenParser->setEnabledBundles($this->enabledBundles);
return $tokenParser;
}
}

View File

@@ -0,0 +1,83 @@
<?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(new TargetPathNode($this, $asset, $name)))
;
}
private function getPathFunction($name)
{
return new \Twig_Node_Expression_Function(
version_compare(\Twig_Environment::VERSION, '1.2.0-DEV', '<')
? new \Twig_Node_Expression_Name('path', $this->getLine()) : 'path',
new \Twig_Node(array(new \Twig_Node_Expression_Constant('_assetic_'.$name, $this->getLine()))),
$this->getLine()
);
}
private function getAssetFunction($path)
{
$arguments = array($path);
if ($this->hasAttribute('package')) {
$arguments[] = new \Twig_Node_Expression_Constant($this->getAttribute('package'), $this->getLine());
}
return new \Twig_Node_Expression_Function(
version_compare(\Twig_Environment::VERSION, '1.2.0-DEV', '<')
? new \Twig_Node_Expression_Name('asset', $this->getLine()) : 'asset',
new \Twig_Node($arguments),
$this->getLine()
);
}
}
class TargetPathNode extends AsseticNode
{
private $node;
private $asset;
private $name;
public function __construct(AsseticNode $node, AssetInterface $asset, $name)
{
$this->node = $node;
$this->asset = $asset;
$this->name = $name;
}
public function compile(\Twig_Compiler $compiler)
{
BaseAsseticNode::compileAssetUrl($compiler, $this->asset, $this->name);
}
public function getLine()
{
return $this->node->getLine();
}
}

View File

@@ -0,0 +1,120 @@
<?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\AsseticFilterFunction;
use Symfony\Bundle\AsseticBundle\Exception\InvalidBundleException;
use Symfony\Component\Templating\TemplateNameParserInterface;
/**
* Assetic node visitor.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticNodeVisitor implements \Twig_NodeVisitorInterface
{
private $templateNameParser;
private $enabledBundles;
private $useNodeName;
public function __construct(TemplateNameParserInterface $templateNameParser, array $enabledBundles)
{
$this->templateNameParser = $templateNameParser;
$this->enabledBundles = $enabledBundles;
$this->useNodeName = version_compare(\Twig_Environment::VERSION, '1.2.0-DEV', '<');
}
public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env)
{
return $node;
}
public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env)
{
if (!$formula = $this->checkNode($node, $env, $name)) {
return $node;
}
// check the bundle
$templateRef = $this->templateNameParser->parse($env->getParser()->getStream()->getFilename());
$bundle = $templateRef->get('bundle');
if ($bundle && !in_array($bundle, $this->enabledBundles)) {
throw new InvalidBundleException($bundle, "the $name() function", $templateRef->getLogicalName(), $this->enabledBundles);
}
list($input, $filters, $options) = $formula;
$line = $node->getLine();
// check context and call either asset() or path()
return new \Twig_Node_Expression_Conditional(
new \Twig_Node_Expression_GetAttr(
new \Twig_Node_Expression_Name('assetic', $line),
new \Twig_Node_Expression_Constant('use_controller', $line),
new \Twig_Node(),
\Twig_TemplateInterface::ARRAY_CALL,
$line
),
new \Twig_Node_Expression_Function(
$this->useNodeName ? new \Twig_Node_Expression_Name('path', $line) : 'path',
new \Twig_Node(array(
new \Twig_Node_Expression_Constant('_assetic_'.$options['name'], $line),
)),
$line
),
new \Twig_Node_Expression_Function(
$this->useNodeName ? new \Twig_Node_Expression_Name('asset', $line) : 'asset',
new \Twig_Node(array($node, new \Twig_Node_Expression_Constant(isset($options['package']) ? $options['package'] : null, $line))),
$line
),
$line
);
}
/**
* Extracts formulae from filter function nodes.
*
* @return array|null The formula
*/
private function checkNode(\Twig_NodeInterface $node, \Twig_Environment $env, & $name = null)
{
if ($node instanceof \Twig_Node_Expression_Function) {
$name = $this->useNodeName
? $node->getNode('name')->getAttribute('name')
: $node->getAttribute('name');
if ($env->getFunction($name) instanceof AsseticFilterFunction) {
$arguments = array();
foreach ($node->getNode('arguments') as $argument) {
$arguments[] = eval('return '.$env->compile($argument).';');
}
$invoker = $env->getExtension('assetic')->getFilterInvoker($name);
$factory = $invoker->getFactory();
$inputs = isset($arguments[0]) ? (array) $arguments[0] : array();
$filters = $invoker->getFilters();
$options = array_replace($invoker->getOptions(), isset($arguments[1]) ? $arguments[1] : array());
if (!isset($options['name'])) {
$options['name'] = $factory->generateAssetName($inputs, $filters);
}
return array($inputs, $filters, $options);
}
}
}
public function getPriority()
{
return 0;
}
}

View File

@@ -0,0 +1,66 @@
<?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;
use Symfony\Bundle\AsseticBundle\Exception\InvalidBundleException;
use Symfony\Component\Templating\TemplateNameParserInterface;
/**
* Assetic token parser.
*
* @author Kris Wallsmith <kris@symfony.com>
*/
class AsseticTokenParser extends BaseAsseticTokenParser
{
private $templateNameParser;
private $enabledBundles;
public function setTemplateNameParser(TemplateNameParserInterface $templateNameParser)
{
$this->templateNameParser = $templateNameParser;
}
public function setEnabledBundles(array $enabledBundles = null)
{
$this->enabledBundles = $enabledBundles;
}
public function parse(\Twig_Token $token)
{
if ($this->templateNameParser && is_array($this->enabledBundles)) {
// check the bundle
$templateRef = null;
try {
$templateRef = $this->templateNameParser->parse($this->parser->getStream()->getFilename());
} catch (\RuntimeException $e) {
// this happens when the filename isn't a Bundle:* url
// and it contains ".."
} catch (\InvalidArgumentException $e) {
// this happens when the filename isn't a Bundle:* url
// but an absolute path instead
}
$bundle = $templateRef ? $templateRef->get('bundle') : null;
if ($bundle && !in_array($bundle, $this->enabledBundles)) {
throw new InvalidBundleException($bundle, "the {% {$this->getTag()} %} tag", $templateRef->getLogicalName(), $this->enabledBundles);
}
}
return parent::parse($token);
}
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

@@ -0,0 +1,10 @@
Changes in version 2.1
----------------------
* Friendlier exception message when using Assetic in a bundle that Assetic
has not been configured to scan
* Assets are no longer dumped to the filesystem when `cache:warmup` is run.
This can only be done using the `assetic:dump` command
* Added support for GSS filter
* Assetic's routes are now automatically added when `use_controller` is
`true`

View File

@@ -0,0 +1,33 @@
{
"name": "symfony/assetic-bundle",
"version": "2.1.0",
"description": "Integrates Assetic into Symfony2",
"keywords": ["assets", "compression", "minification"],
"homepage": "https://github.com/symfony/AsseticBundle",
"type": "symfony-bundle",
"license": "MIT",
"authors": [
{
"name": "Kris Wallsmith",
"email": "kris.wallsmith@gmail.com",
"homepage": "http://kriswallsmith.net/"
}
],
"require": {
"php": ">=5.3.0",
"symfony/framework-bundle": "2.1.*",
"kriswallsmith/assetic": "1.1.*"
},
"suggest": {
"symfony/twig-bundle": "2.1.*"
},
"autoload": {
"psr-0": { "Symfony\\Bundle\\AsseticBundle": "" }
},
"target-dir": "Symfony/Bundle/AsseticBundle",
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev"
}
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./Tests/bootstrap.php"
>
<testsuites>
<testsuite name="AsseticBundle Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<php>
<!-- <server name="SYMFONY" value="/path/to/symfony/src" /> -->
<!-- <server name="ASSETIC" value="/path/to/assetic/src" /> -->
<!-- <server name="TWIG" value="/path/to/twig/lib" /> -->
</php>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
</exclude>
</whitelist>
</filter>
</phpunit>