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>

View File

@@ -0,0 +1,9 @@
language: php
php:
- 5.3
- 5.4
before_script:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install --dev

View File

@@ -0,0 +1,59 @@
<?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\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers processors in Monolog loggers or handlers.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class AddProcessorsPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('monolog.logger')) {
return;
}
foreach ($container->findTaggedServiceIds('monolog.processor') as $id => $tags) {
foreach ($tags as $tag) {
if (!empty($tag['channel']) && !empty($tag['handler'])) {
throw new \InvalidArgumentException(sprintf('you cannot specify both the "handler" and "channel" attributes for the "monolog.processor" tag on service "%s"', $id));
}
if (!empty($tag['handler'])) {
$definition = $container->findDefinition(sprintf('monolog.handler.%s', $tag['handler']));
} elseif (!empty($tag['channel'])) {
if ('app' === $tag['channel']) {
$definition = $container->getDefinition('monolog.logger');
} else {
$definition = $container->getDefinition(sprintf('monolog.logger.%s', $tag['channel']));
}
} else {
$definition = $container->getDefinition('monolog.logger_prototype');
}
if (!empty($tag['method'])) {
$processor = array(new Reference($id), $tag['method']);
} else {
// If no method is defined, fallback to use __invoke
$processor = new Reference($id);
}
$definition->addMethodCall('pushProcessor', array($processor));
}
}
}
}

View File

@@ -0,0 +1,49 @@
<?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\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Definition;
use Monolog\Logger;
/**
* Adds the DebugHandler when the profiler is enabled.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class DebugHandlerPass implements CompilerPassInterface
{
private $channelPass;
public function __construct(LoggerChannelPass $channelPass)
{
$this->channelPass = $channelPass;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('profiler')) {
return;
}
$debugHandler = new Definition('%monolog.handler.debug.class%', array(Logger::DEBUG, true));
$container->setDefinition('monolog.handler.debug', $debugHandler);
foreach ($this->channelPass->getChannels() as $channel) {
$container
->getDefinition($channel === 'app' ? 'monolog.logger' : 'monolog.logger.'.$channel)
->addMethodCall('pushHandler', array(new Reference('monolog.handler.debug')));
}
}
}

View File

@@ -0,0 +1,105 @@
<?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\MonologBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Replaces the default logger by another one with its own channel for tagged services.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class LoggerChannelPass implements CompilerPassInterface
{
protected $channels = array('app');
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('monolog.logger')) {
return;
}
foreach ($container->findTaggedServiceIds('monolog.logger') as $id => $tags) {
foreach ($tags as $tag) {
if (empty($tag['channel']) || 'app' === $tag['channel']) {
continue;
}
$definition = $container->getDefinition($id);
$loggerId = sprintf('monolog.logger.%s', $tag['channel']);
$this->createLogger($tag['channel'], $loggerId, $container);
foreach ($definition->getArguments() as $index => $argument) {
if ($argument instanceof Reference && 'logger' === (string) $argument) {
$definition->replaceArgument($index, new Reference($loggerId, $argument->getInvalidBehavior(), $argument->isStrict()));
}
}
$calls = $definition->getMethodCalls();
foreach ($calls as $i => $call) {
foreach ($call[1] as $index => $argument) {
if ($argument instanceof Reference && 'logger' === (string) $argument) {
$calls[$i][1][$index] = new Reference($loggerId, $argument->getInvalidBehavior(), $argument->isStrict());
}
}
}
$definition->setMethodCalls($calls);
}
}
$handlersToChannels = $container->getParameter('monolog.handlers_to_channels');
foreach ($handlersToChannels as $handler => $channels) {
foreach ($this->processChannels($channels) as $channel) {
try {
$logger = $container->getDefinition($channel === 'app' ? 'monolog.logger' : 'monolog.logger.'.$channel);
} catch (InvalidArgumentException $e) {
$msg = 'Monolog configuration error: The logging channel "'.$channel.'" assigned to the "'.substr($handler, 16).'" handler does not exist.';
throw new \InvalidArgumentException($msg, 0, $e);
}
$logger->addMethodCall('pushHandler', array(new Reference($handler)));
}
}
}
public function getChannels()
{
return $this->channels;
}
protected function processChannels($configuration)
{
if (null === $configuration) {
return $this->channels;
}
if ('inclusive' === $configuration['type']) {
return $configuration['elements'];
}
return array_diff($this->channels, $configuration['elements']);
}
protected function createLogger($channel, $loggerId, ContainerBuilder $container)
{
if (!in_array($channel, $this->channels)) {
$logger = new DefinitionDecorator('monolog.logger_prototype');
$logger->replaceArgument(0, $channel);
$container->setDefinition($loggerId, $logger);
$this->channels[] = $channel;
}
}
}

View File

@@ -0,0 +1,215 @@
<?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\MonologBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
/**
* 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 Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
class Configuration implements ConfigurationInterface
{
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('monolog');
$rootNode
->fixXmlConfig('handler')
->children()
->arrayNode('handlers')
->canBeUnset()
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('member')
->canBeUnset()
->children()
->scalarNode('type')
->isRequired()
->treatNullLike('null')
->beforeNormalization()
->always()
->then(function($v) { return strtolower($v); })
->end()
->end()
->scalarNode('id')->end()
->scalarNode('priority')->defaultValue(0)->end()
->scalarNode('level')->defaultValue('DEBUG')->end()
->booleanNode('bubble')->defaultTrue()->end()
->scalarNode('path')->defaultValue('%kernel.logs_dir%/%kernel.environment%.log')->end() // stream and rotating
->scalarNode('ident')->defaultFalse()->end() // syslog
->scalarNode('facility')->defaultValue('user')->end() // syslog
->scalarNode('max_files')->defaultValue(0)->end() // rotating
->scalarNode('action_level')->defaultValue('WARNING')->end() // fingers_crossed
->scalarNode('activation_strategy')->defaultNull()->end() // fingers_crossed
->booleanNode('stop_buffering')->defaultTrue()->end()// fingers_crossed
->scalarNode('buffer_size')->defaultValue(0)->end() // fingers_crossed and buffer
->scalarNode('handler')->end() // fingers_crossed and buffer
->arrayNode('publisher')
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('id'=> $v); })
->end()
->children()
->scalarNode('id')->end()
->scalarNode('hostname')->end()
->scalarNode('port')->defaultValue(12201)->end()
->scalarNode('chunk_size')->defaultValue(1420)->end()
->end()
->validate()
->ifTrue(function($v) {
return !isset($v['id']) && !isset($v['hostname']);
})
->thenInvalid('What must be set is either the hostname or the id.')
->end()
->end() // gelf
->arrayNode('members') // group
->canBeUnset()
->performNoDeepMerging()
->prototype('scalar')->end()
->end()
->scalarNode('from_email')->end() // swift_mailer and native_mailer
->scalarNode('to_email')->end() // swift_mailer and native_mailer
->scalarNode('subject')->end() // swift_mailer and native_mailer
->arrayNode('email_prototype') // swift_mailer
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('id' => $v); })
->end()
->children()
->scalarNode('id')->isRequired()->end()
->scalarNode('factory-method')->defaultNull()->end()
->end()
->end()
->arrayNode('channels')
->fixXmlConfig('channel', 'elements')
->canBeUnset()
->beforeNormalization()
->ifString()
->then(function($v) { return array('elements' => array($v)); })
->end()
->beforeNormalization()
->ifTrue(function($v) { return is_array($v) && is_numeric(key($v)); })
->then(function($v) { return array('elements' => $v); })
->end()
->validate()
->ifTrue(function($v) { return empty($v); })
->thenUnset()
->end()
->validate()
->always(function ($v) {
$isExclusive = null;
if (isset($v['type'])) {
$isExclusive = 'exclusive' === $v['type'];
}
$elements = array();
foreach ($v['elements'] as $element) {
if (0 === strpos($element, '!')) {
if (false === $isExclusive) {
throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list.');
}
$elements[] = substr($element, 1);
$isExclusive = true;
} else {
if (true === $isExclusive) {
throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list');
}
$elements[] = $element;
$isExclusive = false;
}
}
return array('type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => $elements);
})
->end()
->children()
->scalarNode('type')
->validate()
->ifNotInArray(array('inclusive', 'exclusive'))
->thenInvalid('The type of channels has to be inclusive or exclusive')
->end()
->end()
->arrayNode('elements')
->prototype('scalar')->end()
->end()
->end()
->end()
->scalarNode('formatter')->end()
->end()
->validate()
->ifTrue(function($v) { return ('fingers_crossed' === $v['type'] || 'buffer' === $v['type']) && 1 !== count($v['handler']); })
->thenInvalid('The handler has to be specified to use a FingersCrossedHandler or BufferHandler')
->end()
->validate()
->ifTrue(function($v) { return 'swift_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); })
->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use a SwiftMailerHandler')
->end()
->validate()
->ifTrue(function($v) { return 'native_mailer' === $v['type'] && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); })
->thenInvalid('The sender, recipient and subject have to be specified to use a NativeMailerHandler')
->end()
->validate()
->ifTrue(function($v) { return 'service' === $v['type'] && !isset($v['id']); })
->thenInvalid('The id has to be specified to use a service as handler')
->end()
->validate()
->ifTrue(function($v) { return 'gelf' === $v['type'] && !isset($v['publisher']); })
->thenInvalid('The publisher has to be specified to use a GelfHandler')
->end()
->end()
->validate()
->ifTrue(function($v) { return isset($v['debug']); })
->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler')
->end()
->example(array(
'syslog' => array(
'type' => 'stream',
'path' => '/var/log/symfony.log',
'level' => 'ERROR',
'bubble' => 'false',
'formatter' => 'my_formatter',
'processors' => array('some_callable')
),
'main' => array(
'type' => 'fingers_crossed',
'action_level' => 'WARNING',
'buffer_size' => 30,
'handler' => 'custom',
),
'custom' => array(
'type' => 'service',
'id' => 'my_handler'
)
))
->end()
->end()
;
return $treeBuilder;
}
}

View File

@@ -0,0 +1,289 @@
<?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\MonologBundle\DependencyInjection;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* MonologExtension is an extension for the Monolog library.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
class MonologExtension extends Extension
{
private $nestedHandlers = array();
/**
* Loads the Monolog configuration.
*
* @param array $configs An array of configuration settings
* @param ContainerBuilder $container A ContainerBuilder instance
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
if (isset($config['handlers'])) {
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('monolog.xml');
$container->setAlias('logger', 'monolog.logger');
$handlers = array();
foreach ($config['handlers'] as $name => $handler) {
$handlers[] = array(
'id' => $this->buildHandler($container, $name, $handler),
'priority' => $handler['priority'],
'channels' => isset($handler['channels']) ? $handler['channels'] : null
);
}
$handlers = array_reverse($handlers);
uasort($handlers, function($a, $b) {
if ($a['priority'] == $b['priority']) {
return 0;
}
return $a['priority'] < $b['priority'] ? -1 : 1;
});
$handlersToChannels = array();
foreach ($handlers as $handler) {
if (!in_array($handler['id'], $this->nestedHandlers)) {
$handlersToChannels[$handler['id']] = $handler['channels'];
}
}
$container->setParameter('monolog.handlers_to_channels', $handlersToChannels);
$this->addClassesToCompile(array(
'Monolog\\Formatter\\FormatterInterface',
'Monolog\\Formatter\\LineFormatter',
'Monolog\\Handler\\HandlerInterface',
'Monolog\\Handler\\AbstractHandler',
'Monolog\\Handler\\AbstractProcessingHandler',
'Monolog\\Handler\\StreamHandler',
'Monolog\\Handler\\FingersCrossedHandler',
'Monolog\\Handler\\TestHandler',
'Monolog\\Logger',
'Symfony\\Bridge\\Monolog\\Logger',
'Symfony\\Bridge\\Monolog\\Handler\\DebugHandler',
));
}
}
/**
* 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/monolog';
}
private function buildHandler(ContainerBuilder $container, $name, array $handler)
{
$handlerId = $this->getHandlerId($name);
$definition = new Definition(sprintf('%%monolog.handler.%s.class%%', $handler['type']));
$handler['level'] = is_int($handler['level']) ? $handler['level'] : constant('Monolog\Logger::'.strtoupper($handler['level']));
switch ($handler['type']) {
case 'service':
$container->setAlias($handlerId, $handler['id']);
return $handlerId;
case 'stream':
$definition->setArguments(array(
$handler['path'],
$handler['level'],
$handler['bubble'],
));
break;
case 'firephp':
$definition->setArguments(array(
$handler['level'],
$handler['bubble'],
));
$definition->addTag('kernel.event_listener', array('event' => 'kernel.response', 'method' => 'onKernelResponse'));
break;
case 'gelf':
if (isset($handler['publisher']['id'])) {
$publisherId = $handler['publisher']['id'];
} else {
$publisher = new Definition("%monolog.gelf.publisher.class%", array(
$handler['publisher']['hostname'],
$handler['publisher']['port'],
$handler['publisher']['chunk_size'],
));
$publisherId = 'monolog.gelf.publisher';
$publisher->setPublic(false);
$container->setDefinition($publisherId, $publisher);
}
$definition->setArguments(array(
new Reference($publisherId),
$handler['level'],
$handler['bubble'],
));
break;
case 'chromephp':
$definition->setArguments(array(
$handler['level'],
$handler['bubble'],
));
$definition->addTag('kernel.event_listener', array('event' => 'kernel.response', 'method' => 'onKernelResponse'));
break;
case 'rotating_file':
$definition->setArguments(array(
$handler['path'],
$handler['max_files'],
$handler['level'],
$handler['bubble'],
));
break;
case 'fingers_crossed':
$handler['action_level'] = is_int($handler['action_level']) ? $handler['action_level'] : constant('Monolog\Logger::'.strtoupper($handler['action_level']));
$nestedHandlerId = $this->getHandlerId($handler['handler']);
$this->nestedHandlers[] = $nestedHandlerId;
if (isset($handler['activation_strategy'])) {
$activation = new Reference($handler['activation_strategy']);
} else {
$activation = $handler['action_level'];
}
$definition->setArguments(array(
new Reference($nestedHandlerId),
$activation,
$handler['buffer_size'],
$handler['bubble'],
$handler['stop_buffering'],
));
break;
case 'buffer':
$nestedHandlerId = $this->getHandlerId($handler['handler']);
$this->nestedHandlers[] = $nestedHandlerId;
$definition->setArguments(array(
new Reference($nestedHandlerId),
$handler['buffer_size'],
$handler['level'],
$handler['bubble'],
));
break;
case 'group':
$references = array();
foreach ($handler['members'] as $nestedHandler) {
$nestedHandlerId = $this->getHandlerId($nestedHandler);
$this->nestedHandlers[] = $nestedHandlerId;
$references[] = new Reference($nestedHandlerId);
}
$definition->setArguments(array(
$references,
$handler['bubble'],
));
break;
case 'syslog':
$definition->setArguments(array(
$handler['ident'],
$handler['facility'],
$handler['level'],
$handler['bubble'],
));
break;
case 'swift_mailer':
if (isset($handler['email_prototype'])) {
if (!empty($handler['email_prototype']['method'])) {
$prototype = array(new Reference($handler['email_prototype']['id']), $handler['email_prototype']['method']);
} else {
$prototype = new Reference($handler['email_prototype']['id']);
}
} else {
$message = new Definition('Swift_Message');
$message->setFactoryService('mailer');
$message->setFactoryMethod('createMessage');
$message->setPublic(false);
$message->addMethodCall('setFrom', array($handler['from_email']));
$message->addMethodCall('setTo', array($handler['to_email']));
$message->addMethodCall('setSubject', array($handler['subject']));
$messageId = sprintf('%s.mail_prototype', $handlerId);
$container->setDefinition($messageId, $message);
$prototype = new Reference($messageId);
}
$definition->setArguments(array(
new Reference('mailer'),
$prototype,
$handler['level'],
$handler['bubble'],
));
break;
case 'native_mailer':
$definition->setArguments(array(
$handler['to_email'],
$handler['subject'],
$handler['from_email'],
$handler['level'],
$handler['bubble'],
));
break;
// Handlers using the constructor of AbstractHandler without adding their own arguments
case 'test':
case 'null':
case 'debug':
$definition->setArguments(array(
$handler['level'],
$handler['bubble'],
));
break;
default:
throw new \InvalidArgumentException(sprintf('Invalid handler type "%s" given for handler "%s"', $handler['type'], $name));
}
if (!empty($handler['formatter'])) {
$definition->addMethodCall('setFormatter', array(new Reference($handler['formatter'])));
}
$container->setDefinition($handlerId, $definition);
return $handlerId;
}
private function getHandlerId($name)
{
return sprintf('monolog.handler.%s', $name);
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-2012 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More