From 7c6a784da9e08e8396bc50abeff64431e5908847 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 28 Dec 2014 19:57:17 +0100 Subject: [PATCH 01/13] [FrameworkBundle] removed the need to always load templating_php.xml --- .../FrameworkExtension.php | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c1f880b85a6c9..07301b249c3e4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -458,7 +458,6 @@ private function registerRequestConfiguration(array $config, ContainerBuilder $c private function registerTemplatingConfiguration(array $config, $ide, ContainerBuilder $container, XmlFileLoader $loader) { $loader->load('templating.xml'); - $loader->load('templating_php.xml'); $links = array( 'textmate' => 'txmt://open?url=file://%%f&line=%%l', @@ -468,12 +467,9 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB ); $container->setParameter('templating.helper.code.file_link_format', isset($links[$ide]) ? $links[$ide] : $ide); - $container->setParameter('templating.helper.form.resources', $config['form']['resources']); $container->setParameter('fragment.renderer.hinclude.global_template', $config['hinclude_default_template']); if ($container->getParameter('kernel.debug')) { - $loader->load('templating_debug.xml'); - $logger = new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE); $container->getDefinition('templating.loader.cache') @@ -482,24 +478,7 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB $container->getDefinition('templating.loader.chain') ->addTag('monolog.logger', array('channel' => 'templating')) ->addMethodCall('setLogger', array($logger)); - - $container->setDefinition('templating.engine.php', $container->findDefinition('debug.templating.engine.php')); - $container->setAlias('debug.templating.engine.php', 'templating.engine.php'); - } - - // create package definitions and add them to the assets helper - $defaultPackage = $this->createPackageDefinition($container, $config['assets_base_urls']['http'], $config['assets_base_urls']['ssl'], $config['assets_version'], $config['assets_version_format']); - $container->setDefinition('templating.asset.default_package', $defaultPackage); - $namedPackages = array(); - foreach ($config['packages'] as $name => $package) { - $namedPackage = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format'], $name); - $container->setDefinition('templating.asset.package.'.$name, $namedPackage); - $namedPackages[$name] = new Reference('templating.asset.package.'.$name); } - $container->getDefinition('templating.helper.assets')->setArguments(array( - new Reference('templating.asset.default_package'), - $namedPackages, - )); if (!empty($config['loaders'])) { $loaders = array_map(function ($loader) { return new Reference($loader); }, $config['loaders']); @@ -531,6 +510,31 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB )); if (in_array('php', $config['engines'], true)) { + $loader->load('templating_php.xml'); + + $container->setParameter('templating.helper.form.resources', $config['form']['resources']); + + // create package definitions and add them to the assets helper + $defaultPackage = $this->createPackageDefinition($container, $config['assets_base_urls']['http'], $config['assets_base_urls']['ssl'], $config['assets_version'], $config['assets_version_format']); + $container->setDefinition('templating.asset.default_package', $defaultPackage); + $namedPackages = array(); + foreach ($config['packages'] as $name => $package) { + $namedPackage = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format'], $name); + $container->setDefinition('templating.asset.package.'.$name, $namedPackage); + $namedPackages[$name] = new Reference('templating.asset.package.'.$name); + } + $container->getDefinition('templating.helper.assets')->setArguments(array( + new Reference('templating.asset.default_package'), + $namedPackages, + )); + + if ($container->getParameter('kernel.debug')) { + $loader->load('templating_debug.xml'); + + $container->setDefinition('templating.engine.php', $container->findDefinition('debug.templating.engine.php')); + $container->setAlias('debug.templating.engine.php', 'templating.engine.php'); + } + $this->addClassesToCompile(array( 'Symfony\\Component\\Templating\\Storage\\FileStorage', 'Symfony\\Bundle\\FrameworkBundle\\Templating\\PhpEngine', From 759d99849f4777b2634bb533155a3881658fd385 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 28 Dec 2014 20:02:59 +0100 Subject: [PATCH 02/13] [TwigBundle] removed the Container dependency on ActionsExtension --- .../Compiler/ExtensionPass.php | 4 +++ .../TwigBundle/Extension/ActionsExtension.php | 28 ++++++++++++++----- .../TwigBundle/Resources/config/twig.xml | 3 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index 069083d27f0f0..641c5df155b5f 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -27,6 +27,10 @@ public function process(ContainerBuilder $container) $container->getDefinition('twig.loader.filesystem')->addMethodCall('addPath', array(dirname(dirname($reflClass->getFileName())).'/Resources/views/Form')); } + if ($container->has('fragment.handler')) { + $container->getDefinition('twig.extension.actions')->addTag('twig.extension'); + } + if ($container->has('translator')) { $container->getDefinition('twig.extension.trans')->addTag('twig.extension'); } diff --git a/src/Symfony/Bundle/TwigBundle/Extension/ActionsExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/ActionsExtension.php index be96d69c04f24..7dce11181934d 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/ActionsExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/ActionsExtension.php @@ -13,6 +13,7 @@ use Symfony\Bundle\TwigBundle\TokenParser\RenderTokenParser; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpKernel\Fragment\FragmentHandler; /** * Twig extension for Symfony actions helper. @@ -23,16 +24,26 @@ */ class ActionsExtension extends \Twig_Extension { - private $container; + private $handler; /** - * Constructor. + * @param FragmentHandler|ContainerInterface $handler * - * @param ContainerInterface $container The service container + * @deprecated Passing a ContainerInterface as a first argument is deprecated as of 2.7 and will be removed in 3.0. */ - public function __construct(ContainerInterface $container) + public function __construct($handler) { - $this->container = $container; + if ($handler instanceof FragmentHandler) { + $this->handler = $handler; + } elseif ($handler instanceof ContainerInterface) { + trigger_error(sprintf('The ability to pass a ContainerInterface instance as a first argument to %s was deprecated in 2.7 and will be removed in 3.0. Please, pass a FragmentHandler instance instead.', __METHOD__), E_USER_DEPRECATED); + + $this->handler = $handler->get('fragment.handler'); + } else { + throw new \BadFunctionCallException(sprintf('%s takes a FragmentHandler or a ContainerInterface object as its first argument.', __METHOD__)); + } + + $this->handler = $handler; } /** @@ -41,11 +52,14 @@ public function __construct(ContainerInterface $container) * @param string $uri A URI * @param array $options An array of options * - * @see Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver::render() + * @see FragmentHandler::render() */ public function renderUri($uri, array $options = array()) { - return $this->container->get('templating.helper.actions')->render($uri, $options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'inline'; + unset($options['strategy']); + + return $this->handler->render($uri, $strategy, $options); } /** diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 3c81983dd3bea..4ff841db1cef1 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -71,8 +71,7 @@ - - + From bc02843660f36bc216f07033f7a7eb7d83a093f7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 29 Dec 2014 10:48:52 +0100 Subject: [PATCH 03/13] [TwigBundle] always load the exception listener if the templating.engines is not present --- .../Compiler/ExceptionListenerPass.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExceptionListenerPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExceptionListenerPass.php index 18d98b356dfed..9fbfd65950a53 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExceptionListenerPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExceptionListenerPass.php @@ -28,9 +28,11 @@ public function process(ContainerBuilder $container) } // register the exception controller only if Twig is enabled - $engines = $container->getParameter('templating.engines'); - if (!in_array('twig', $engines)) { - $container->removeDefinition('twig.exception_listener'); + if ($container->hasParameter('templating.engines')) { + $engines = $container->getParameter('templating.engines'); + if (!in_array('twig', $engines)) { + $container->removeDefinition('twig.exception_listener'); + } } } } From c12534295958c29423b38c8f41b50129cb496731 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 2 Jan 2015 19:33:24 +0100 Subject: [PATCH 04/13] [FrameworkBundle] refactored asset named packages to make it reusable in Twig --- .../Compiler/TemplatingAssetHelperPass.php | 32 +++++------- .../FrameworkExtension.php | 50 ++++++++----------- .../Resources/config/assets.xml | 37 ++++++++++++++ .../Resources/config/templating_php.xml | 26 ---------- .../TemplatingAssetHelperPassTest.php | 4 +- 5 files changed, 71 insertions(+), 78 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index 39a4e13bbd143..2aaeac386f552 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -27,27 +27,22 @@ public function process(ContainerBuilder $container) $assetsHelperDefinition = $container->getDefinition('templating.helper.assets'); $args = $assetsHelperDefinition->getArguments(); - if ('request' === $this->getPackageScope($container, $args[0])) { - $assetsHelperDefinition->setScope('request'); - - return; - } - - if (!array_key_exists(1, $args)) { - return; + // add tagged packages + $namedPackages = $args[1]; + foreach ($container->findTaggedServiceIds('templating.asset_package') as $id => $attributes) { + $name = isset($attributes['name']) ? $attributes['name'] : $id; + $namedPackages[$name] = $package = new Reference($id); } + $assetsHelperDefinition->replaceArgument(1, $namedPackages); - if (!is_array($args[1])) { - return; - } - - foreach ($args[1] as $arg) { - if ('request' === $this->getPackageScope($container, $arg)) { - $assetsHelperDefinition->setScope('request'); - - break; + // fix helper scope + $scope = $this->getPackageScope($container, $args[0]); + foreach ($namedPackages as $package) { + if ('request' === $this->getPackageScope($container, $package)) { + $scope = 'request'; } } + $assetsHelperDefinition->setScope($scope); } private function getPackageScope(ContainerBuilder $container, $package) @@ -59,8 +54,5 @@ private function getPackageScope(ContainerBuilder $container, $package) if ($package instanceof Definition) { return $package->getScope(); } - - // Someone did some voodoo with a compiler pass. So we ignore this - // 'package'. Can we be sure, it's a package anyway? } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 07301b249c3e4..322bcd589d1ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -458,6 +458,9 @@ private function registerRequestConfiguration(array $config, ContainerBuilder $c private function registerTemplatingConfiguration(array $config, $ide, ContainerBuilder $container, XmlFileLoader $loader) { $loader->load('templating.xml'); + $loader->load('assets.xml'); + + $this->createPackageDefinitions($config, $container); $links = array( 'textmate' => 'txmt://open?url=file://%%f&line=%%l', @@ -513,20 +516,7 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB $loader->load('templating_php.xml'); $container->setParameter('templating.helper.form.resources', $config['form']['resources']); - - // create package definitions and add them to the assets helper - $defaultPackage = $this->createPackageDefinition($container, $config['assets_base_urls']['http'], $config['assets_base_urls']['ssl'], $config['assets_version'], $config['assets_version_format']); - $container->setDefinition('templating.asset.default_package', $defaultPackage); - $namedPackages = array(); - foreach ($config['packages'] as $name => $package) { - $namedPackage = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format'], $name); - $container->setDefinition('templating.asset.package.'.$name, $namedPackage); - $namedPackages[$name] = new Reference('templating.asset.package.'.$name); - } - $container->getDefinition('templating.helper.assets')->setArguments(array( - new Reference('templating.asset.default_package'), - $namedPackages, - )); + $container->getDefinition('templating.helper.assets')->replaceArgument(0, new Reference('templating.asset.default_package')); if ($container->getParameter('kernel.debug')) { $loader->load('templating_debug.xml'); @@ -556,6 +546,19 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB } } + private function createPackageDefinitions(array $config, ContainerBuilder $container) + { + // create package definitions and add them to the assets helper + $defaultPackage = $this->createPackageDefinition($container, $config['assets_base_urls']['http'], $config['assets_base_urls']['ssl'], $config['assets_version'], $config['assets_version_format']); + $container->setDefinition('templating.asset.default_package', $defaultPackage); + + foreach ($config['packages'] as $name => $package) { + $namedPackage = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format'], $name); + $def = $container->setDefinition('templating.asset.package.'.$name, $namedPackage); + $def->addTag('templating.asset_package', array('name' => $name)); + } + } + /** * Returns a definition for an asset package. */ @@ -575,12 +578,7 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt if ($httpUrls == $sslUrls) { $package = new DefinitionDecorator('templating.asset.url_package'); - $package - ->setPublic(false) - ->replaceArgument(0, $sslUrls) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; + $package->setPublic(false)->setArguments(array($sslUrls, $version, $format)); return $package; } @@ -588,20 +586,12 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt $prefix = $name ? 'templating.asset.package.'.$name : 'templating.asset.default_package'; $httpPackage = new DefinitionDecorator('templating.asset.url_package'); - $httpPackage - ->replaceArgument(0, $httpUrls) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; + $httpPackage->setArguments(array($httpUrls, $version, $format)); $container->setDefinition($prefix.'.http', $httpPackage); if ($sslUrls) { $sslPackage = new DefinitionDecorator('templating.asset.url_package'); - $sslPackage - ->replaceArgument(0, $sslUrls) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; + $sslPackage->setArguments(array($sslUrls, $version, $format)); } else { $sslPackage = new DefinitionDecorator('templating.asset.path_package'); $sslPackage diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml new file mode 100644 index 0000000000000..90d935906d5a9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -0,0 +1,37 @@ + + + + + + Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage + Symfony\Component\Templating\Asset\UrlPackage + Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml index 6e482f8573e51..e309d3cd9fbf7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml @@ -19,9 +19,6 @@ Symfony\Component\Form\Extension\Templating\TemplatingRendererEngine Symfony\Component\Form\FormRenderer Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables - Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage - Symfony\Component\Templating\Asset\UrlPackage - Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory @@ -43,29 +40,6 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php index 3a096715e160b..c3d0325eb8315 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php @@ -35,7 +35,7 @@ public function testFindLowestScopeInDefaultPackageWithReference($scope) $defaultPackage->setScope($scope); $container->setDefinition('default_package', $defaultPackage); - $definition = new Definition('stdClass', array(new Reference('default_package'))); + $definition = new Definition('stdClass', array(new Reference('default_package'), array())); $container->setDefinition('templating.helper.assets', $definition); $profilerPass = new TemplatingAssetHelperPass(); @@ -52,7 +52,7 @@ public function testFindLowestScopeInDefaultPackageWithDefinition($scope) $defaultPackage = new Definition('stdClass'); $defaultPackage->setScope($scope); - $definition = new Definition('stdClass', array($defaultPackage)); + $definition = new Definition('stdClass', array($defaultPackage, array())); $container->setDefinition('templating.helper.assets', $definition); $profilerPass = new TemplatingAssetHelperPass(); From afca9ba1ccb7e3290ad1cf9a3652f713183e68b3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 2 Jan 2015 20:47:08 +0100 Subject: [PATCH 05/13] [TwigBundle] decoupled the assets extension from the assets helper --- .../Twig/Extension/AssetPackagesExtension.php | 165 ++++++++++++++++++ .../TwigBundle/Extension/AssetsExtension.php | 4 + .../TwigBundle/Resources/config/twig.xml | 7 +- 3 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php diff --git a/src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php new file mode 100644 index 0000000000000..7753978e21dd5 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Twig\Extension; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Templating\Asset\PackageInterface; + +/** + * Twig extension for Symfony asset packages. + * + * @author Fabien Potencier + */ +class AssetPackagesExtension extends \Twig_Extension +{ + private $defaultPackage; + private $namedPackages = array(); + private $requestStack; + + /** + * @param PackageInterface $defaultPackage The default package + * @param array $namedPackages Additional packages indexed by name + */ + public function __construct(PackageInterface $defaultPackage, array $namedPackages = array(), RequestStack $requestStack = null) + { + $this->defaultPackage = $defaultPackage; + + foreach ($namedPackages as $name => $package) { + $this->addPackage($name, $package); + } + + $this->requestStack = $requestStack; + } + + /** + * Sets the default package. + * + * @param PackageInterface $defaultPackage The default package + */ + public function setDefaultPackage(PackageInterface $defaultPackage) + { + $this->defaultPackage = $defaultPackage; + } + + /** + * Adds an asset package to the helper. + * + * @param string $name The package name + * @param PackageInterface $package The package + */ + public function addPackage($name, PackageInterface $package) + { + $this->namedPackages[$name] = $package; + } + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('asset', array($this, 'getAssetUrl')), + new \Twig_SimpleFunction('assets_version', array($this, 'getAssetsVersion')), + ); + } + + /** + * Returns the public path of an asset. + * + * Absolute paths (i.e. http://...) are returned unmodified. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * @param bool $absolute Whether to return an absolute URL or a relative one + * @param string|bool|null $version A specific version + * + * @return string A public path which takes into account the base path and URL path + */ + public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null) + { + $url = $this->getPackage($packageName)->getUrl($path, $version); + + if (!$absolute) { + return $url; + } + + return $this->ensureUrlIsAbsolute($url); + } + + /** + * Returns the version of the assets in a package. + * + * @param string $packageName + * + * @return int + */ + public function getAssetsVersion($packageName = null) + { + return $this->getPackage($packageName)->getVersion(); + } + + /** + * Returns an asset package. + * + * @param string $name The name of the package or null for the default package + * + * @return PackageInterface An asset package + * + * @throws \InvalidArgumentException If there is no package by that name + */ + private function getPackage($name = null) + { + if (null === $name) { + return $this->defaultPackage; + } + + if (!isset($this->namedPackages[$name])) { + throw new \InvalidArgumentException(sprintf('There is no "%s" asset package.', $name)); + } + + return $this->namedPackages[$name]; + } + + /** + * Ensures an URL is absolute, if possible. + * + * @param string $url The URL that has to be absolute + * + * @throws \RuntimeException + * + * @return string The absolute URL + */ + private function ensureUrlIsAbsolute($url) + { + if (false !== strpos($url, '://') || 0 === strpos($url, '//')) { + return $url; + } + + if (!$this->requestStack) { + throw new \RuntimeException('To generate an absolute URL for an asset, the Symfony Routing component is required.'); + } + + return $this->requestStack->getMasterRequest()->getUriForPath($url); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'asset_packages'; + } +} diff --git a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php index d596f97e528fc..1de9f8dd00296 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php @@ -11,6 +11,8 @@ namespace Symfony\Bundle\TwigBundle\Extension; +trigger_error('Symfony\Bundle\TwigBundle\Extension\AssetsExtension was deprecated in 2.7 and will be removed in 3.0. Please use Symfony\Component\Twig\Extension\AssetPackagesExtension instead.', E_USER_DEPRECATED); + use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Routing\RequestContext; @@ -18,6 +20,8 @@ * Twig extension for Symfony assets helper. * * @author Fabien Potencier + * + * @deprecated Deprecated in 2.7, to be removed in 3.0. Use Symfony\Component\Twig\Extension\AssetPackagesExtension instead. */ class AssetsExtension extends \Twig_Extension { diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 4ff841db1cef1..871c9c1eb2901 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -11,7 +11,7 @@ Symfony\Bundle\TwigBundle\TwigEngine Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer Symfony\Bridge\Twig\Extension\TranslationExtension - Symfony\Bundle\TwigBundle\Extension\AssetsExtension + Symfony\Component\Twig\Extension\AssetPackagesExtension Symfony\Bundle\TwigBundle\Extension\ActionsExtension Symfony\Bridge\Twig\Extension\CodeExtension Symfony\Bridge\Twig\Extension\RoutingExtension @@ -66,8 +66,9 @@ - - + + + From 14c02358fd0969276bbb199ec406853fba38fd21 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 12:34:36 +0100 Subject: [PATCH 06/13] [Asset] moved the Asset classes from the Templating Component to a new one --- src/Symfony/Component/Asset/.gitignore | 3 + src/Symfony/Component/Asset/CHANGELOG.md | 7 ++ src/Symfony/Component/Asset/LICENSE | 19 +++ src/Symfony/Component/Asset/Package.php | 79 +++++++++++++ .../Component/Asset/PackageInterface.php | 37 ++++++ src/Symfony/Component/Asset/Packages.php | 108 ++++++++++++++++++ src/Symfony/Component/Asset/PathPackage.php | 73 ++++++++++++ src/Symfony/Component/Asset/README.md | 13 +++ src/Symfony/Component/Asset/UrlPackage.php | 82 +++++++++++++ src/Symfony/Component/Asset/composer.json | 31 +++++ src/Symfony/Component/Asset/phpunit.xml.dist | 29 +++++ .../Component/Templating/Asset/Package.php | 64 +---------- .../Templating/Asset/PackageInterface.php | 22 +--- .../Templating/Asset/PathPackage.php | 58 +--------- .../Component/Templating/Asset/UrlPackage.php | 67 +---------- .../Component/Templating/composer.json | 3 +- 16 files changed, 503 insertions(+), 192 deletions(-) create mode 100644 src/Symfony/Component/Asset/.gitignore create mode 100644 src/Symfony/Component/Asset/CHANGELOG.md create mode 100644 src/Symfony/Component/Asset/LICENSE create mode 100644 src/Symfony/Component/Asset/Package.php create mode 100644 src/Symfony/Component/Asset/PackageInterface.php create mode 100644 src/Symfony/Component/Asset/Packages.php create mode 100644 src/Symfony/Component/Asset/PathPackage.php create mode 100644 src/Symfony/Component/Asset/README.md create mode 100644 src/Symfony/Component/Asset/UrlPackage.php create mode 100644 src/Symfony/Component/Asset/composer.json create mode 100644 src/Symfony/Component/Asset/phpunit.xml.dist diff --git a/src/Symfony/Component/Asset/.gitignore b/src/Symfony/Component/Asset/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Asset/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Asset/CHANGELOG.md b/src/Symfony/Component/Asset/CHANGELOG.md new file mode 100644 index 0000000000000..619a423402ada --- /dev/null +++ b/src/Symfony/Component/Asset/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +2.7.0 +----- + + * added the component diff --git a/src/Symfony/Component/Asset/LICENSE b/src/Symfony/Component/Asset/LICENSE new file mode 100644 index 0000000000000..43028bc600f26 --- /dev/null +++ b/src/Symfony/Component/Asset/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 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. diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php new file mode 100644 index 0000000000000..cf119fe60f217 --- /dev/null +++ b/src/Symfony/Component/Asset/Package.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +/** + * The basic package will add a version to asset URLs. + * + * @author Kris Wallsmith + */ +class Package implements PackageInterface +{ + private $version; + private $format; + + /** + * Constructor. + * + * @param string $version The package version + * @param string $format The format used to apply the version + */ + public function __construct($version = null, $format = '') + { + $this->version = $version; + $this->format = $format ?: '%s?%s'; + } + + /** + * {@inheritdoc} + */ + public function getVersion() + { + return $this->version; + } + + /** + * {@inheritdoc} + */ + public function getUrl($path, $version = null) + { + if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + return $path; + } + + return $this->applyVersion($path, $version); + } + + /** + * Applies version to the supplied path. + * + * @param string $path A path + * @param string|bool|null $version A specific version + * + * @return string The versionized path + */ + protected function applyVersion($path, $version = null) + { + $version = null !== $version ? $version : $this->version; + if (null === $version || false === $version) { + return $path; + } + + $versionized = sprintf($this->format, ltrim($path, '/'), $version); + + if ($path && '/' == $path[0]) { + $versionized = '/'.$versionized; + } + + return $versionized; + } +} diff --git a/src/Symfony/Component/Asset/PackageInterface.php b/src/Symfony/Component/Asset/PackageInterface.php new file mode 100644 index 0000000000000..be13b114cbf50 --- /dev/null +++ b/src/Symfony/Component/Asset/PackageInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +/** + * Asset package interface. + * + * @author Kris Wallsmith + */ +interface PackageInterface +{ + /** + * Returns the asset package version. + * + * @return string The version string + */ + public function getVersion(); + + /** + * Returns an absolute or root-relative public path. + * + * @param string $path A path + * @param string|bool|null $version A specific version for the path + * + * @return string The public path + */ + public function getUrl($path, $version = null); +} diff --git a/src/Symfony/Component/Asset/Packages.php b/src/Symfony/Component/Asset/Packages.php new file mode 100644 index 0000000000000..89cceb046307d --- /dev/null +++ b/src/Symfony/Component/Asset/Packages.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +/** + * Helps manage asset URLs. + * + * @author Fabien Potencier + * @author Kris Wallsmith + */ +class Packages +{ + private $defaultPackage; + private $packages = array(); + + /** + * @param PackageInterface $defaultPackage The default package + * @param PackageInterface[] $packages Additional packages indexed by name + */ + public function __construct(PackageInterface $defaultPackage, array $packages = array()) + { + $this->defaultPackage = $defaultPackage; + + foreach ($packages as $name => $package) { + $this->addPackage($name, $package); + } + } + + /** + * Sets the default package. + * + * @param PackageInterface $defaultPackage The default package + */ + public function setDefaultPackage(PackageInterface $defaultPackage) + { + $this->defaultPackage = $defaultPackage; + } + + /** + * Adds a package. + * + * @param string $name The package name + * @param PackageInterface $package The package + */ + public function addPackage($name, PackageInterface $package) + { + $this->packages[$name] = $package; + } + + /** + * Returns an asset package. + * + * @param string $name The name of the package or null for the default package + * + * @return PackageInterface An asset package + * + * @throws \InvalidArgumentException If there is no package by that name + */ + public function getPackage($name = null) + { + if (null === $name) { + return $this->defaultPackage; + } + + if (!isset($this->packages[$name])) { + throw new \InvalidArgumentException(sprintf('There is no "%s" asset package.', $name)); + } + + return $this->packages[$name]; + } + + /** + * Gets the version to add to public URL. + * + * @param string $packageName A package name + * + * @return string The current version + */ + public function getVersion($packageName = null) + { + return $this->getPackage($packageName)->getVersion(); + } + + /** + * Returns the public path. + * + * Absolute paths (i.e. http://...) are returned unmodified. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * @param string|bool|null $version A specific version + * + * @return string A public path which takes into account the base path and URL path + */ + public function getUrl($path, $packageName = null, $version = null) + { + return $this->getPackage($packageName)->getUrl($path, $version); + } +} diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php new file mode 100644 index 0000000000000..64c1a697a57e0 --- /dev/null +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +/** + * The path packages adds a version and a base path to asset URLs. + * + * @author Kris Wallsmith + */ +class PathPackage extends Package +{ + private $basePath; + + /** + * Constructor. + * + * @param string $basePath The base path to be prepended to relative paths + * @param string $version The package version + * @param string $format The format used to apply the version + */ + public function __construct($basePath = null, $version = null, $format = null) + { + parent::__construct($version, $format); + + if (!$basePath) { + $this->basePath = '/'; + } else { + if ('/' != $basePath[0]) { + $basePath = '/'.$basePath; + } + + $this->basePath = rtrim($basePath, '/').'/'; + } + } + + /** + * {@inheritdoc} + */ + public function getUrl($path, $version = null) + { + if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + return $path; + } + + $url = $this->applyVersion($path, $version); + + // apply the base path + if ('/' !== substr($url, 0, 1)) { + $url = $this->basePath.$url; + } + + return $url; + } + + /** + * Returns the base path. + * + * @return string The base path + */ + public function getBasePath() + { + return $this->basePath; + } +} diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md new file mode 100644 index 0000000000000..9f49ffc69dc0b --- /dev/null +++ b/src/Symfony/Component/Asset/README.md @@ -0,0 +1,13 @@ +Asset Component +=============== + +Asset provides classes to manage asset URLs. + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Asset/ + $ composer.phar install + $ phpunit diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php new file mode 100644 index 0000000000000..63bfa0d9bc070 --- /dev/null +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +/** + * The URL packages adds a version and a base URL to asset URLs. + * + * @author Kris Wallsmith + */ +class UrlPackage extends Package +{ + private $baseUrls; + + /** + * Constructor. + * + * @param string|array $baseUrls Base asset URLs + * @param string $version The package version + * @param string $format The format used to apply the version + */ + public function __construct($baseUrls = array(), $version = null, $format = null) + { + parent::__construct($version, $format); + + if (!is_array($baseUrls)) { + $baseUrls = (array) $baseUrls; + } + + $this->baseUrls = array(); + foreach ($baseUrls as $baseUrl) { + $this->baseUrls[] = rtrim($baseUrl, '/'); + } + } + + /** + * {@inheritdoc} + */ + public function getUrl($path, $version = null) + { + if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + return $path; + } + + $url = $this->applyVersion($path, $version); + + if ($url && '/' != $url[0]) { + $url = '/'.$url; + } + + return $this->getBaseUrl($path).$url; + } + + /** + * Returns the base URL for a path. + * + * @param string $path + * + * @return string The base URL + */ + public function getBaseUrl($path) + { + switch ($count = count($this->baseUrls)) { + case 0: + return ''; + + case 1: + return $this->baseUrls[0]; + + default: + return $this->baseUrls[fmod(hexdec(substr(hash('sha256', $path), 0, 10)), $count)]; + } + } +} diff --git a/src/Symfony/Component/Asset/composer.json b/src/Symfony/Component/Asset/composer.json new file mode 100644 index 0000000000000..f7b16eff7500d --- /dev/null +++ b/src/Symfony/Component/Asset/composer.json @@ -0,0 +1,31 @@ +{ + "name": "symfony/asset", + "type": "library", + "description": "Symfony Asset Component", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-0": { "Symfony\\Component\\Asset\\": "" } + }, + "target-dir": "Symfony/Component/Asset", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/src/Symfony/Component/Asset/phpunit.xml.dist b/src/Symfony/Component/Asset/phpunit.xml.dist new file mode 100644 index 0000000000000..34ca2f294395d --- /dev/null +++ b/src/Symfony/Component/Asset/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./vendor + ./Tests + + + + diff --git a/src/Symfony/Component/Templating/Asset/Package.php b/src/Symfony/Component/Templating/Asset/Package.php index 02a1269bd95ad..1690ac9bf713e 100644 --- a/src/Symfony/Component/Templating/Asset/Package.php +++ b/src/Symfony/Component/Templating/Asset/Package.php @@ -11,69 +11,15 @@ namespace Symfony\Component\Templating\Asset; +use Symfony\Component\Asset\Package as AssetPackage; + /** * The basic package will add a version to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, to be removed in 3.0. Use the Asset Component instead. */ -class Package implements PackageInterface +class Package extends AssetPackage implements PackageInterface { - private $version; - private $format; - - /** - * Constructor. - * - * @param string $version The package version - * @param string $format The format used to apply the version - */ - public function __construct($version = null, $format = '') - { - $this->version = $version; - $this->format = $format ?: '%s?%s'; - } - - /** - * {@inheritdoc} - */ - public function getVersion() - { - return $this->version; - } - - /** - * {@inheritdoc} - */ - public function getUrl($path, $version = null) - { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { - return $path; - } - - return $this->applyVersion($path, $version); - } - - /** - * Applies version to the supplied path. - * - * @param string $path A path - * @param string|bool|null $version A specific version - * - * @return string The versionized path - */ - protected function applyVersion($path, $version = null) - { - $version = null !== $version ? $version : $this->version; - if (null === $version || false === $version) { - return $path; - } - - $versionized = sprintf($this->format, ltrim($path, '/'), $version); - - if ($path && '/' == $path[0]) { - $versionized = '/'.$versionized; - } - - return $versionized; - } } diff --git a/src/Symfony/Component/Templating/Asset/PackageInterface.php b/src/Symfony/Component/Templating/Asset/PackageInterface.php index 7317b555ac476..d65297cbfecf5 100644 --- a/src/Symfony/Component/Templating/Asset/PackageInterface.php +++ b/src/Symfony/Component/Templating/Asset/PackageInterface.php @@ -11,27 +11,15 @@ namespace Symfony\Component\Templating\Asset; +use Symfony\Component\Asset\PackageInterface as AssetPackageInterface; + /** * Asset package interface. * * @author Kris Wallsmith + * + * @deprecated since 2.7, to be removed in 3.0. Use the Asset Component instead. */ -interface PackageInterface +interface PackageInterface extends AssetPackageInterface { - /** - * Returns the asset package version. - * - * @return string The version string - */ - public function getVersion(); - - /** - * Returns an absolute or root-relative public path. - * - * @param string $path A path - * @param string|bool|null $version A specific version for the path - * - * @return string The public path - */ - public function getUrl($path, $version = null); } diff --git a/src/Symfony/Component/Templating/Asset/PathPackage.php b/src/Symfony/Component/Templating/Asset/PathPackage.php index 1806107f6dfca..75090757ca9c2 100644 --- a/src/Symfony/Component/Templating/Asset/PathPackage.php +++ b/src/Symfony/Component/Templating/Asset/PathPackage.php @@ -11,63 +11,15 @@ namespace Symfony\Component\Templating\Asset; +use Symfony\Component\Asset\PathPackage as AssetPathPackage; + /** * The path packages adds a version and a base path to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, to be removed in 3.0. Use the Asset Component instead. */ -class PathPackage extends Package +class PathPackage extends AssetPathPackage implements PackageInterface { - private $basePath; - - /** - * Constructor. - * - * @param string $basePath The base path to be prepended to relative paths - * @param string $version The package version - * @param string $format The format used to apply the version - */ - public function __construct($basePath = null, $version = null, $format = null) - { - parent::__construct($version, $format); - - if (!$basePath) { - $this->basePath = '/'; - } else { - if ('/' != $basePath[0]) { - $basePath = '/'.$basePath; - } - - $this->basePath = rtrim($basePath, '/').'/'; - } - } - - /** - * {@inheritdoc} - */ - public function getUrl($path, $version = null) - { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { - return $path; - } - - $url = $this->applyVersion($path, $version); - - // apply the base path - if ('/' !== substr($url, 0, 1)) { - $url = $this->basePath.$url; - } - - return $url; - } - - /** - * Returns the base path. - * - * @return string The base path - */ - public function getBasePath() - { - return $this->basePath; - } } diff --git a/src/Symfony/Component/Templating/Asset/UrlPackage.php b/src/Symfony/Component/Templating/Asset/UrlPackage.php index 00a21670f4459..6853444d29739 100644 --- a/src/Symfony/Component/Templating/Asset/UrlPackage.php +++ b/src/Symfony/Component/Templating/Asset/UrlPackage.php @@ -11,72 +11,15 @@ namespace Symfony\Component\Templating\Asset; +use Symfony\Component\Asset\UrlPackage as AssetUrlPackage; + /** * The URL packages adds a version and a base URL to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, to be removed in 3.0. Use the Asset Component instead. */ -class UrlPackage extends Package +class UrlPackage extends AssetUrlPackage implements PackageInterface { - private $baseUrls; - - /** - * Constructor. - * - * @param string|array $baseUrls Base asset URLs - * @param string $version The package version - * @param string $format The format used to apply the version - */ - public function __construct($baseUrls = array(), $version = null, $format = null) - { - parent::__construct($version, $format); - - if (!is_array($baseUrls)) { - $baseUrls = (array) $baseUrls; - } - - $this->baseUrls = array(); - foreach ($baseUrls as $baseUrl) { - $this->baseUrls[] = rtrim($baseUrl, '/'); - } - } - - /** - * {@inheritdoc} - */ - public function getUrl($path, $version = null) - { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { - return $path; - } - - $url = $this->applyVersion($path, $version); - - if ($url && '/' != $url[0]) { - $url = '/'.$url; - } - - return $this->getBaseUrl($path).$url; - } - - /** - * Returns the base URL for a path. - * - * @param string $path - * - * @return string The base URL - */ - public function getBaseUrl($path) - { - switch ($count = count($this->baseUrls)) { - case 0: - return ''; - - case 1: - return $this->baseUrls[0]; - - default: - return $this->baseUrls[fmod(hexdec(substr(hash('sha256', $path), 0, 10)), $count)]; - } - } } diff --git a/src/Symfony/Component/Templating/composer.json b/src/Symfony/Component/Templating/composer.json index ab98c9d00ec39..2ae135554ee88 100644 --- a/src/Symfony/Component/Templating/composer.json +++ b/src/Symfony/Component/Templating/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/asset": "~2.7" }, "require-dev": { "psr/log": "~1.0" From 21ddf4de5e2602a4ea39b731703ef5c09f547879 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 12:54:32 +0100 Subject: [PATCH 07/13] refactored PHP and Twig asset helpers to use the new Asset component --- src/Symfony/Bridge/Twig/CHANGELOG.md | 5 ++ ...ckagesExtension.php => AssetExtension.php} | 75 +++---------------- src/Symfony/Bridge/Twig/composer.json | 1 + .../Compiler/AddAssetPackagesPass.php | 61 +++++++++++++++ .../Compiler/TemplatingAssetHelperPass.php | 37 ++------- .../FrameworkExtension.php | 1 - .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/assets.xml | 5 ++ .../Compiler/ExtensionPass.php | 4 + .../TwigBundle/Resources/config/twig.xml | 6 +- 10 files changed, 98 insertions(+), 99 deletions(-) rename src/Symfony/Bridge/Twig/Extension/{AssetPackagesExtension.php => AssetExtension.php} (53%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 4be010ba20e56..be949ee860924 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +2.7.0 +----- + + * added AssetExtension (provides the `asset` function) + 2.5.0 ----- diff --git a/src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php similarity index 53% rename from src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php rename to src/Symfony/Bridge/Twig/Extension/AssetExtension.php index 7753978e21dd5..cf4a92c922829 100644 --- a/src/Symfony/Bridge/Twig/Extension/AssetPackagesExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -12,59 +12,26 @@ namespace Symfony\Component\Twig\Extension; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Templating\Asset\PackageInterface; +use Symfony\Component\Asset\Packages; /** - * Twig extension for Symfony asset packages. + * Twig extension for the Symfony Asset component. * * @author Fabien Potencier */ -class AssetPackagesExtension extends \Twig_Extension +class AssetExtension extends \Twig_Extension { - private $defaultPackage; - private $namedPackages = array(); + private $packages; private $requestStack; - /** - * @param PackageInterface $defaultPackage The default package - * @param array $namedPackages Additional packages indexed by name - */ - public function __construct(PackageInterface $defaultPackage, array $namedPackages = array(), RequestStack $requestStack = null) + public function __construct(Packages $packages, RequestStack $requestStack = null) { - $this->defaultPackage = $defaultPackage; - - foreach ($namedPackages as $name => $package) { - $this->addPackage($name, $package); - } - + $this->packages = $packages; $this->requestStack = $requestStack; } /** - * Sets the default package. - * - * @param PackageInterface $defaultPackage The default package - */ - public function setDefaultPackage(PackageInterface $defaultPackage) - { - $this->defaultPackage = $defaultPackage; - } - - /** - * Adds an asset package to the helper. - * - * @param string $name The package name - * @param PackageInterface $package The package - */ - public function addPackage($name, PackageInterface $package) - { - $this->namedPackages[$name] = $package; - } - - /** - * Returns a list of functions to add to the existing list. - * - * @return array An array of functions + * {@inheritdoc} */ public function getFunctions() { @@ -88,7 +55,7 @@ public function getFunctions() */ public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null) { - $url = $this->getPackage($packageName)->getUrl($path, $version); + $url = $this->packages->getUrl($path, $packageName, $version); if (!$absolute) { return $url; @@ -106,29 +73,7 @@ public function getAssetUrl($path, $packageName = null, $absolute = false, $vers */ public function getAssetsVersion($packageName = null) { - return $this->getPackage($packageName)->getVersion(); - } - - /** - * Returns an asset package. - * - * @param string $name The name of the package or null for the default package - * - * @return PackageInterface An asset package - * - * @throws \InvalidArgumentException If there is no package by that name - */ - private function getPackage($name = null) - { - if (null === $name) { - return $this->defaultPackage; - } - - if (!isset($this->namedPackages[$name])) { - throw new \InvalidArgumentException(sprintf('There is no "%s" asset package.', $name)); - } - - return $this->namedPackages[$name]; + return $this->packages->getVersion($packageName); } /** @@ -146,7 +91,7 @@ private function ensureUrlIsAbsolute($url) return $url; } - if (!$this->requestStack) { + if (null === $this->requestStack) { throw new \RuntimeException('To generate an absolute URL for an asset, the Symfony Routing component is required.'); } diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 8d2af5c52cac6..99f8f2e75083c 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -37,6 +37,7 @@ }, "suggest": { "symfony/finder": "", + "symfony/asset": "For using the AssetExtension", "symfony/form": "For using the FormExtension", "symfony/http-kernel": "For using the HttpKernelExtension", "symfony/routing": "For using the RoutingExtension", diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php new file mode 100644 index 0000000000000..65c4969c9132e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +class AddAssetPackagesPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('templating.asset.packages')) { + return; + } + + $defaultPackage = new Reference('templating.asset.default_package'); + $namedPackages = array(); + + // tagged packages + foreach ($container->findTaggedServiceIds('templating.asset_package') as $id => $attributes) { + $name = isset($attributes['name']) ? $attributes['name'] : $id; + $namedPackages[$name] = $package = new Reference($id); + } + + // fix helper scope + $scope = $this->getPackageScope($container, $defaultPackage); + foreach ($namedPackages as $package) { + if ('request' === $this->getPackageScope($container, $package)) { + $scope = 'request'; + } + } + + $container->getDefinition('templating.asset.packages') + ->setScope($scope) + ->replaceArgument(0, $defaultPackage) + ->replaceArgument(1, $namedPackages) + ; + } + + private function getPackageScope(ContainerBuilder $container, $package) + { + if ($package instanceof Reference) { + return $container->findDefinition((string) $package)->getScope(); + } + + if ($package instanceof Definition) { + return $package->getScope(); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index 2aaeac386f552..c859210fc1fee 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -13,8 +13,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; class TemplatingAssetHelperPass implements CompilerPassInterface { @@ -24,35 +22,16 @@ public function process(ContainerBuilder $container) return; } - $assetsHelperDefinition = $container->getDefinition('templating.helper.assets'); - $args = $assetsHelperDefinition->getArguments(); - - // add tagged packages - $namedPackages = $args[1]; - foreach ($container->findTaggedServiceIds('templating.asset_package') as $id => $attributes) { - $name = isset($attributes['name']) ? $attributes['name'] : $id; - $namedPackages[$name] = $package = new Reference($id); - } - $assetsHelperDefinition->replaceArgument(1, $namedPackages); - - // fix helper scope - $scope = $this->getPackageScope($container, $args[0]); - foreach ($namedPackages as $package) { - if ('request' === $this->getPackageScope($container, $package)) { - $scope = 'request'; - } + if (!$container->hasDefinition('templating.asset.packages')) { + return; } - $assetsHelperDefinition->setScope($scope); - } - private function getPackageScope(ContainerBuilder $container, $package) - { - if ($package instanceof Reference) { - return $container->findDefinition((string) $package)->getScope(); - } + $packages = $container->getDefinition('templating.asset.packages'); - if ($package instanceof Definition) { - return $package->getScope(); - } + $container->getDefinition('templating.helper.assets') + ->setScope($packages->getScope()) + ->replaceArgument(0, $packages->getArgument(0)) + ->replaceArgument(1, $packages->getArgument(1)) + ; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 322bcd589d1ea..24afc791b7e7a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -516,7 +516,6 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB $loader->load('templating_php.xml'); $container->setParameter('templating.helper.form.resources', $config['form']['resources']); - $container->getDefinition('templating.helper.assets')->replaceArgument(0, new Reference('templating.asset.default_package')); if ($container->getParameter('kernel.debug')) { $loader->load('templating_debug.xml'); diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 10896786c9f05..b82df190e55e1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAssetPackagesPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingAssetHelperPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; @@ -76,6 +77,7 @@ public function build(ContainerBuilder $container) // but as late as possible to get resolved parameters $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); + $container->addCompilerPass(new AddAssetPackagesPass()); $container->addCompilerPass(new TemplatingAssetHelperPass()); $container->addCompilerPass(new AddConstraintValidatorsPass()); $container->addCompilerPass(new AddValidatorInitializersPass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 90d935906d5a9..2685d2fc60d9f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -11,6 +11,11 @@ + + + + + diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index 641c5df155b5f..1938b4ba9be83 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -31,6 +31,10 @@ public function process(ContainerBuilder $container) $container->getDefinition('twig.extension.actions')->addTag('twig.extension'); } + if ($container->has('templating.asset.packages')) { + $container->getDefinition('twig.extension.assets')->addTag('twig.extension'); + } + if ($container->has('translator')) { $container->getDefinition('twig.extension.trans')->addTag('twig.extension'); } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 871c9c1eb2901..260691c8ca90f 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -11,7 +11,7 @@ Symfony\Bundle\TwigBundle\TwigEngine Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer Symfony\Bridge\Twig\Extension\TranslationExtension - Symfony\Component\Twig\Extension\AssetPackagesExtension + Symfony\Component\Twig\Extension\AssetExtension Symfony\Bundle\TwigBundle\Extension\ActionsExtension Symfony\Bridge\Twig\Extension\CodeExtension Symfony\Bridge\Twig\Extension\RoutingExtension @@ -65,9 +65,7 @@ - - - + From ee66d6978c5796d79f8a403be767fd3abb41c2fb Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 13:38:13 +0100 Subject: [PATCH 08/13] added RequestPackage to removed the request scope from PathPackage --- .../FrameworkExtension.php | 2 - .../Resources/config/assets.xml | 4 +- .../Templating/Asset/PathPackage.php | 4 ++ src/Symfony/Component/Asset/PathPackage.php | 2 +- src/Symfony/Component/Asset/README.md | 3 ++ .../Component/Asset/RequestPackage.php | 45 +++++++++++++++++++ 6 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/Asset/RequestPackage.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 24afc791b7e7a..aa00bcfc28834 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -567,7 +567,6 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt $package = new DefinitionDecorator('templating.asset.path_package'); $package ->setPublic(false) - ->setScope('request') ->replaceArgument(1, $version) ->replaceArgument(2, $format) ; @@ -594,7 +593,6 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt } else { $sslPackage = new DefinitionDecorator('templating.asset.path_package'); $sslPackage - ->setScope('request') ->replaceArgument(1, $version) ->replaceArgument(2, $format) ; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 2685d2fc60d9f..9523f2ab27d08 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -5,7 +5,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage + Symfony\Component\Asset\RequestPackage Symfony\Component\Templating\Asset\UrlPackage Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory @@ -17,7 +17,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php index 6aa8c58824669..8d44869b76383 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php @@ -14,10 +14,14 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\Asset\PathPackage as BasePathPackage; +trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Asset\RequestPackage instead.', E_USER_DEPRECATED); + /** * The path packages adds a version and a base path to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use Symfony\Component\Asset\RequestPackage instead. */ class PathPackage extends BasePathPackage { diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php index 64c1a697a57e0..78e026a040205 100644 --- a/src/Symfony/Component/Asset/PathPackage.php +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -55,7 +55,7 @@ public function getUrl($path, $version = null) // apply the base path if ('/' !== substr($url, 0, 1)) { - $url = $this->basePath.$url; + $url = $this->getBasePath().$url; } return $url; diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md index 9f49ffc69dc0b..d1799a6102c73 100644 --- a/src/Symfony/Component/Asset/README.md +++ b/src/Symfony/Component/Asset/README.md @@ -3,6 +3,9 @@ Asset Component Asset provides classes to manage asset URLs. +```php +``` + Resources --------- diff --git a/src/Symfony/Component/Asset/RequestPackage.php b/src/Symfony/Component/Asset/RequestPackage.php new file mode 100644 index 0000000000000..a180933d4f7a9 --- /dev/null +++ b/src/Symfony/Component/Asset/RequestPackage.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Asset\PathPackage as BasePathPackage; + +/** + * @author Fabien Potencier + */ +class RequestPackage extends BasePathPackage +{ + private $requestStack; + + /** + * Constructor. + * + * @param RequestStack $request The request stack + * @param string $version The version + * @param string $format The version format + */ + public function __construct(RequestStack $requestStack, $version = null, $format = null) + { + $this->requestStack = $requestStack; + + parent::__construct(null, $version, $format); + } + + /** + * {@inheritdoc} + */ + public function getBasePath() + { + return $this->requestStack->getCurrentRequest()->getBasePath().'/'; + } +} From 3e0a09041c9f11f7f4c0469c0229c10ff0d0f821 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 13:45:42 +0100 Subject: [PATCH 09/13] added RequestAwarePackageFactory to removed the request scope from PackageFactory --- .../DependencyInjection/FrameworkExtension.php | 1 - .../Bundle/FrameworkBundle/Resources/config/assets.xml | 7 +++---- .../FrameworkBundle/Templating/Asset/PackageFactory.php | 4 ++++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index aa00bcfc28834..89db25b29c853 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -602,7 +602,6 @@ private function createPackageDefinition(ContainerBuilder $container, array $htt $package = new DefinitionDecorator('templating.asset.request_aware_package'); $package ->setPublic(false) - ->setScope('request') ->replaceArgument(1, $prefix.'.http') ->replaceArgument(2, $prefix.'.ssl') ; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 9523f2ab27d08..82967b320f2ba 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -6,8 +6,8 @@ Symfony\Component\Asset\RequestPackage - Symfony\Component\Templating\Asset\UrlPackage - Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory + Symfony\Component\Asset\UrlPackage + Symfony\Component\Asset\RequestPackageFactory @@ -30,13 +30,12 @@ - - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php index 0a63a29cd6cce..f2326c5fc4fd1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php @@ -11,6 +11,8 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Asset; +trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageInterface is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Asset\RequestPackageFactory instead.', E_USER_DEPRECATED); + use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\Asset\PackageInterface; @@ -19,6 +21,8 @@ * Creates packages based on whether the current request is secure. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use Symfony\Component\Asset\RequestPackageFactory instead. */ class PackageFactory { From 051016aa60b8c3e3f6e5eceaaa0da96e21eb656a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 13:46:31 +0100 Subject: [PATCH 10/13] [FrameworkBundle] removed obsolete scope management for asset packages --- .../Compiler/AddAssetPackagesPass.php | 20 ------------------- .../Compiler/TemplatingAssetHelperPass.php | 1 - 2 files changed, 21 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php index 65c4969c9132e..71e46e1a86f7c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php @@ -33,29 +33,9 @@ public function process(ContainerBuilder $container) $namedPackages[$name] = $package = new Reference($id); } - // fix helper scope - $scope = $this->getPackageScope($container, $defaultPackage); - foreach ($namedPackages as $package) { - if ('request' === $this->getPackageScope($container, $package)) { - $scope = 'request'; - } - } - $container->getDefinition('templating.asset.packages') - ->setScope($scope) ->replaceArgument(0, $defaultPackage) ->replaceArgument(1, $namedPackages) ; } - - private function getPackageScope(ContainerBuilder $container, $package) - { - if ($package instanceof Reference) { - return $container->findDefinition((string) $package)->getScope(); - } - - if ($package instanceof Definition) { - return $package->getScope(); - } - } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index c859210fc1fee..e18e9348da5b9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -29,7 +29,6 @@ public function process(ContainerBuilder $container) $packages = $container->getDefinition('templating.asset.packages'); $container->getDefinition('templating.helper.assets') - ->setScope($packages->getScope()) ->replaceArgument(0, $packages->getArgument(0)) ->replaceArgument(1, $packages->getArgument(1)) ; From 86c2ffdef6673b229071a7a610cfd3f7b8b67555 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 19:03:55 +0100 Subject: [PATCH 11/13] simplified asset management and make classes more reusable outside of Symfony Full Stack --- .../Bridge/Twig/Extension/AssetExtension.php | 2 +- .../Compiler/AddAssetPackagesPass.php | 41 ------ .../Compiler/TemplatingAssetHelperPass.php | 17 +-- .../DependencyInjection/Configuration.php | 1 + .../FrameworkExtension.php | 64 +++------ .../FrameworkBundle/FrameworkBundle.php | 4 - .../Resources/config/assets.xml | 25 +--- .../Templating/Asset/PackageFactory.php | 4 +- .../Templating/Asset/PathPackage.php | 4 +- .../TemplatingAssetHelperPassTest.php | 121 ------------------ ...uestPackage.php => RequestPathPackage.php} | 5 +- .../Component/Asset/RequestUrlPackage.php | 94 ++++++++++++++ src/Symfony/Component/Asset/UrlPackage.php | 2 +- 13 files changed, 127 insertions(+), 257 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php rename src/Symfony/Component/Asset/{RequestPackage.php => RequestPathPackage.php} (87%) create mode 100644 src/Symfony/Component/Asset/RequestUrlPackage.php diff --git a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php index cf4a92c922829..858cec85348d4 100644 --- a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -105,6 +105,6 @@ private function ensureUrlIsAbsolute($url) */ public function getName() { - return 'asset_packages'; + return 'asset'; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php deleted file mode 100644 index 71e46e1a86f7c..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAssetPackagesPass.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; - -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class AddAssetPackagesPass implements CompilerPassInterface -{ - public function process(ContainerBuilder $container) - { - if (!$container->hasDefinition('templating.asset.packages')) { - return; - } - - $defaultPackage = new Reference('templating.asset.default_package'); - $namedPackages = array(); - - // tagged packages - foreach ($container->findTaggedServiceIds('templating.asset_package') as $id => $attributes) { - $name = isset($attributes['name']) ? $attributes['name'] : $id; - $namedPackages[$name] = $package = new Reference($id); - } - - $container->getDefinition('templating.asset.packages') - ->replaceArgument(0, $defaultPackage) - ->replaceArgument(1, $namedPackages) - ; - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index e18e9348da5b9..7ccecb60f9fb1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -14,23 +14,12 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +/** + * @deprecated since 2.7, will be removed in 3.0 + */ class TemplatingAssetHelperPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { - if (!$container->hasDefinition('templating.helper.assets')) { - return; - } - - if (!$container->hasDefinition('templating.asset.packages')) { - return; - } - - $packages = $container->getDefinition('templating.asset.packages'); - - $container->getDefinition('templating.helper.assets') - ->replaceArgument(0, $packages->getArgument(0)) - ->replaceArgument(1, $packages->getArgument(1)) - ; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 9354a549805a1..195234f603f8f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -311,6 +311,7 @@ private function addRequestSection(ArrayNodeDefinition $rootNode) private function addTemplatingSection(ArrayNodeDefinition $rootNode) { + /** @deprecated, should be removed in 3.0 */ $organizeUrls = function ($urls) { $urls += array( 'http' => array(), diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 89db25b29c853..ac293814e47b9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -517,6 +517,12 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB $container->setParameter('templating.helper.form.resources', $config['form']['resources']); + $packages = $container->getDefinition('templating.asset.packages'); + $container->getDefinition('templating.helper.assets') + ->replaceArgument(0, $packages->getArgument(0)) + ->replaceArgument(1, $packages->getArgument(1)) + ; + if ($container->getParameter('kernel.debug')) { $loader->load('templating_debug.xml'); @@ -551,62 +557,30 @@ private function createPackageDefinitions(array $config, ContainerBuilder $conta $defaultPackage = $this->createPackageDefinition($container, $config['assets_base_urls']['http'], $config['assets_base_urls']['ssl'], $config['assets_version'], $config['assets_version_format']); $container->setDefinition('templating.asset.default_package', $defaultPackage); + $namedPackages = array(); foreach ($config['packages'] as $name => $package) { - $namedPackage = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format'], $name); - $def = $container->setDefinition('templating.asset.package.'.$name, $namedPackage); - $def->addTag('templating.asset_package', array('name' => $name)); + $namedPackage[$name] = $this->createPackageDefinition($container, $package['base_urls']['http'], $package['base_urls']['ssl'], $package['version'], $package['version_format']); } + + $container->getDefinition('templating.asset.packages') + ->replaceArgument(0, $defaultPackage) + ->replaceArgument(1, $namedPackages) + ; } /** * Returns a definition for an asset package. */ - private function createPackageDefinition(ContainerBuilder $container, array $httpUrls, array $sslUrls, $version, $format, $name = null) + private function createPackageDefinition(ContainerBuilder $container, array $httpUrls, array $sslUrls, $version, $format) { - if (!$httpUrls) { - $package = new DefinitionDecorator('templating.asset.path_package'); - $package - ->setPublic(false) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; + $package = new DefinitionDecorator('templating.asset.package'); - return $package; - } - - if ($httpUrls == $sslUrls) { - $package = new DefinitionDecorator('templating.asset.url_package'); - $package->setPublic(false)->setArguments(array($sslUrls, $version, $format)); - - return $package; - } - - $prefix = $name ? 'templating.asset.package.'.$name : 'templating.asset.default_package'; - - $httpPackage = new DefinitionDecorator('templating.asset.url_package'); - $httpPackage->setArguments(array($httpUrls, $version, $format)); - $container->setDefinition($prefix.'.http', $httpPackage); - - if ($sslUrls) { - $sslPackage = new DefinitionDecorator('templating.asset.url_package'); - $sslPackage->setArguments(array($sslUrls, $version, $format)); - } else { - $sslPackage = new DefinitionDecorator('templating.asset.path_package'); - $sslPackage - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; - } - $container->setDefinition($prefix.'.ssl', $sslPackage); - - $package = new DefinitionDecorator('templating.asset.request_aware_package'); - $package + return $package ->setPublic(false) - ->replaceArgument(1, $prefix.'.http') - ->replaceArgument(2, $prefix.'.ssl') + ->replaceArgument(1, array_merge($httpUrls, $sslUrls), $version) + ->replaceArgument(2, $version) + ->replaceArgument(3, $format) ; - - return $package; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index b82df190e55e1..09f7bd66b8aa4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -16,8 +16,6 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; -use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAssetPackagesPass; -use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingAssetHelperPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass; @@ -77,8 +75,6 @@ public function build(ContainerBuilder $container) // but as late as possible to get resolved parameters $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); - $container->addCompilerPass(new AddAssetPackagesPass()); - $container->addCompilerPass(new TemplatingAssetHelperPass()); $container->addCompilerPass(new AddConstraintValidatorsPass()); $container->addCompilerPass(new AddValidatorInitializersPass()); $container->addCompilerPass(new AddConsoleCommandPass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 82967b320f2ba..686ee4b3026a3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -4,38 +4,19 @@ 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"> - - Symfony\Component\Asset\RequestPackage - Symfony\Component\Asset\UrlPackage - Symfony\Component\Asset\RequestPackageFactory - - + - + + - - - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php index f2326c5fc4fd1..7c68b1d1e1964 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Asset; -trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageInterface is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Asset\RequestPackageFactory instead.', E_USER_DEPRECATED); +trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageInterface is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED); use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -22,7 +22,7 @@ * * @author Kris Wallsmith * - * @deprecated since 2.7, will be removed in 3.0. Use Symfony\Component\Asset\RequestPackageFactory instead. + * @deprecated since 2.7, will be removed in 3.0. */ class PackageFactory { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php index 8d44869b76383..9207e8fb0df0e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php @@ -14,14 +14,14 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\Asset\PathPackage as BasePathPackage; -trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Asset\RequestPackage instead.', E_USER_DEPRECATED); +trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Asset\RequestPathPackage instead.', E_USER_DEPRECATED); /** * The path packages adds a version and a base path to asset URLs. * * @author Kris Wallsmith * - * @deprecated since 2.7, will be removed in 3.0. Use Symfony\Component\Asset\RequestPackage instead. + * @deprecated since 2.7, will be removed in 3.0. Use Symfony\Component\Asset\RequestPathPackage instead. */ class PathPackage extends BasePathPackage { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php deleted file mode 100644 index c3d0325eb8315..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php +++ /dev/null @@ -1,121 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; - -use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingAssetHelperPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class TemplatingAssetHelperPassTest extends \PHPUnit_Framework_TestCase -{ - public function getScopesTests() - { - return array( - array('container'), - array('request'), - ); - } - - /** @dataProvider getScopesTests */ - public function testFindLowestScopeInDefaultPackageWithReference($scope) - { - $container = new ContainerBuilder(); - - $defaultPackage = new Definition('stdClass'); - $defaultPackage->setScope($scope); - $container->setDefinition('default_package', $defaultPackage); - - $definition = new Definition('stdClass', array(new Reference('default_package'), array())); - $container->setDefinition('templating.helper.assets', $definition); - - $profilerPass = new TemplatingAssetHelperPass(); - $profilerPass->process($container); - - $this->assertSame($scope, $definition->getScope()); - } - - /** @dataProvider getScopesTests */ - public function testFindLowestScopeInDefaultPackageWithDefinition($scope) - { - $container = new ContainerBuilder(); - - $defaultPackage = new Definition('stdClass'); - $defaultPackage->setScope($scope); - - $definition = new Definition('stdClass', array($defaultPackage, array())); - $container->setDefinition('templating.helper.assets', $definition); - - $profilerPass = new TemplatingAssetHelperPass(); - $profilerPass->process($container); - - $this->assertSame($scope, $definition->getScope()); - } - - /** @dataProvider getScopesTests */ - public function testFindLowestScopeInNamedPackageWithReference($scope) - { - $container = new ContainerBuilder(); - - $defaultPackage = new Definition('stdClass'); - $container->setDefinition('default_package', $defaultPackage); - - $aPackage = new Definition('stdClass'); - $container->setDefinition('a_package', $aPackage); - - $bPackage = new Definition('stdClass'); - $bPackage->setScope($scope); - $container->setDefinition('b_package', $bPackage); - - $cPackage = new Definition('stdClass'); - $container->setDefinition('c_package', $cPackage); - - $definition = new Definition('stdClass', array(new Reference('default_package'), array( - new Reference('a_package'), - new Reference('b_package'), - new Reference('c_package'), - ))); - $container->setDefinition('templating.helper.assets', $definition); - - $profilerPass = new TemplatingAssetHelperPass(); - $profilerPass->process($container); - - $this->assertSame($scope, $definition->getScope()); - } - - /** @dataProvider getScopesTests */ - public function testFindLowestScopeInNamedPackageWithDefinition($scope) - { - $container = new ContainerBuilder(); - - $defaultPackage = new Definition('stdClass'); - - $aPackage = new Definition('stdClass'); - - $bPackage = new Definition('stdClass'); - $bPackage->setScope($scope); - - $cPackage = new Definition('stdClass'); - - $definition = new Definition('stdClass', array($defaultPackage, array( - $aPackage, - $bPackage, - $cPackage, - ))); - $container->setDefinition('templating.helper.assets', $definition); - - $profilerPass = new TemplatingAssetHelperPass(); - $profilerPass->process($container); - - $this->assertSame($scope, $definition->getScope()); - } -} diff --git a/src/Symfony/Component/Asset/RequestPackage.php b/src/Symfony/Component/Asset/RequestPathPackage.php similarity index 87% rename from src/Symfony/Component/Asset/RequestPackage.php rename to src/Symfony/Component/Asset/RequestPathPackage.php index a180933d4f7a9..0b2478ecc310a 100644 --- a/src/Symfony/Component/Asset/RequestPackage.php +++ b/src/Symfony/Component/Asset/RequestPathPackage.php @@ -12,18 +12,15 @@ namespace Symfony\Component\Asset; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Asset\PathPackage as BasePathPackage; /** * @author Fabien Potencier */ -class RequestPackage extends BasePathPackage +class RequestPathPackage extends PathPackage { private $requestStack; /** - * Constructor. - * * @param RequestStack $request The request stack * @param string $version The version * @param string $format The version format diff --git a/src/Symfony/Component/Asset/RequestUrlPackage.php b/src/Symfony/Component/Asset/RequestUrlPackage.php new file mode 100644 index 0000000000000..ff5ff1d66c083 --- /dev/null +++ b/src/Symfony/Component/Asset/RequestUrlPackage.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset; + +use Symfony\Component\HttpFoundation\RequestStack; + +/** + * @author Fabien Potencier + */ +class RequestUrlPackage implements PackageInterface +{ + private $version; + private $requestStack; + private $package; + private $sslPackage; + + /** + * @param RequestStack $request The request stack + * @param string $version The version + * @param string $format The version format + */ + public function __construct(RequestStack $requestStack, $baseUrls = array(), $version = null, $format = null) + { + $this->requestStack = $requestStack; + $this->version = $version; + + list($allUrls, $sslUrls) = $this->organizeUrls($baseUrls); + + if (!$allUrls) { + $this->package = new RequestPathPackage($requestStack, $version, $format); + } elseif ($allUrls === $sslUrls) { + $this->package = new UrlPackage($allUrls, $version, $format); + } else { + $this->package = new UrlPackage($allUrls, $version, $format); + + if ($sslUrls) { + $this->sslPackage = new UrlPackage($sslUrls, $version, $format); + } else { + $this->sslPackage = new RequestPathPackage($version, $format); + } + } + } + + /** + * {@inheritdoc} + */ + public function getVersion() + { + return $this->version; + } + + /** + * {@inheritdoc} + */ + public function getUrl($path, $version = null) + { + if (null === $this->sslPackage) { + return $this->package->getUrl($path, $version); + } + + if (($request = $this->requestStack->getCurrentRequest()) && $request->isSecure()) { + return $this->sslPackage->getUrl($path, $version); + } + + return $this->package->getUrl($path, $version); + } + + private function organizeUrls($urls) + { + $sslUrls = isset($urls['ssl']) ? $urls['ssl'] : array(); + $allUrls = array_merge(isset($urls['http']) ? $urls['http'] : array(), $sslUrls); + foreach ($urls as $i => $url) { + if (!is_integer($i)) { + continue; + } + + $allUrls[] = $url; + if (0 === strpos($url, 'https://') || 0 === strpos($url, '//')) { + $sslUrls[] = $url; + } + } + + return array($allUrls, $sslUrls); + } +} diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php index 63bfa0d9bc070..54645d370ba12 100644 --- a/src/Symfony/Component/Asset/UrlPackage.php +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -18,7 +18,7 @@ */ class UrlPackage extends Package { - private $baseUrls; + protected $baseUrls; /** * Constructor. From af15c78992a23c6426b6d1f5475525aeb3d67fba Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 21:38:55 +0100 Subject: [PATCH 12/13] made things more flexible and more consistent --- .../Bridge/Twig/Extension/AssetExtension.php | 2 +- src/Symfony/Component/Asset/Package.php | 13 +- src/Symfony/Component/Asset/Packages.php | 6 +- src/Symfony/Component/Asset/PathPackage.php | 8 +- src/Symfony/Component/Asset/README.md | 146 +++++++++++++++++- .../Component/Asset/RequestPathPackage.php | 19 ++- .../Component/Asset/RequestUrlPackage.php | 72 +++++---- src/Symfony/Component/Asset/UrlPackage.php | 16 +- 8 files changed, 226 insertions(+), 56 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php index 858cec85348d4..b35b957a27eb9 100644 --- a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -87,7 +87,7 @@ public function getAssetsVersion($packageName = null) */ private function ensureUrlIsAbsolute($url) { - if (false !== strpos($url, '://') || 0 === strpos($url, '//')) { + if (false !== strpos($url, '://') || '//' === substr($url, 0, 2)) { return $url; } diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php index cf119fe60f217..cb2d6de708763 100644 --- a/src/Symfony/Component/Asset/Package.php +++ b/src/Symfony/Component/Asset/Package.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Asset; /** - * The basic package will add a version to asset URLs. + * Basic package that adds a version to asset URLs. * * @author Kris Wallsmith */ @@ -46,13 +46,18 @@ public function getVersion() */ public function getUrl($path, $version = null) { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + if ($this->isAbsoluteUrl($path)) { return $path; } return $this->applyVersion($path, $version); } + protected function isAbsoluteUrl($url) + { + return false !== strpos($url, '://') || '//' === substr($url, 0, 2); + } + /** * Applies version to the supplied path. * @@ -63,8 +68,8 @@ public function getUrl($path, $version = null) */ protected function applyVersion($path, $version = null) { - $version = null !== $version ? $version : $this->version; - if (null === $version || false === $version) { + $version = $version ?: $this->version; + if (!$version) { return $path; } diff --git a/src/Symfony/Component/Asset/Packages.php b/src/Symfony/Component/Asset/Packages.php index 89cceb046307d..988dc09473a61 100644 --- a/src/Symfony/Component/Asset/Packages.php +++ b/src/Symfony/Component/Asset/Packages.php @@ -26,7 +26,7 @@ class Packages * @param PackageInterface $defaultPackage The default package * @param PackageInterface[] $packages Additional packages indexed by name */ - public function __construct(PackageInterface $defaultPackage, array $packages = array()) + public function __construct(PackageInterface $defaultPackage = null, array $packages = array()) { $this->defaultPackage = $defaultPackage; @@ -68,6 +68,10 @@ public function addPackage($name, PackageInterface $package) public function getPackage($name = null) { if (null === $name) { + if (null === $this->defaultPackage) { + throw new \LogicException('There is no default asset package, configure one first.'); + } + return $this->defaultPackage; } diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php index 78e026a040205..105b7f2af13d7 100644 --- a/src/Symfony/Component/Asset/PathPackage.php +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Asset; /** - * The path packages adds a version and a base path to asset URLs. + * Package that adds a base path to asset URLs in addition to a version. * * @author Kris Wallsmith */ @@ -27,7 +27,7 @@ class PathPackage extends Package * @param string $version The package version * @param string $format The format used to apply the version */ - public function __construct($basePath = null, $version = null, $format = null) + public function __construct($basePath, $version = null, $format = null) { parent::__construct($version, $format); @@ -47,7 +47,7 @@ public function __construct($basePath = null, $version = null, $format = null) */ public function getUrl($path, $version = null) { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + if ($this->isAbsoluteUrl($path)) { return $path; } @@ -55,7 +55,7 @@ public function getUrl($path, $version = null) // apply the base path if ('/' !== substr($url, 0, 1)) { - $url = $this->getBasePath().$url; + return $this->getBasePath().$url; } return $url; diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md index d1799a6102c73..99ad22dfe5e48 100644 --- a/src/Symfony/Component/Asset/README.md +++ b/src/Symfony/Component/Asset/README.md @@ -1,9 +1,153 @@ Asset Component =============== -Asset provides classes to manage asset URLs. +The Asset component manages asset URLs. + +Versioned Asset URLs +-------------------- + +The basic `Package` adds a version to generated asset URLs: + +```php +use Symfony\Component\Asset\Package; + +$package = new Package('v1'); + +echo $package->getUrl('/me.png'); +// /me.png?v1 +``` + +The default format can be configured: + +```php +$package = new Package('v1', '%s?version=%s'); + +echo $package->getUrl('/me.png'); +// /me.png?version=v1 + +// put the version before the path +$package = new Package('v1', 'version-%2$s/%1$s'); + +echo $package->getUrl('/me.png'); +// /version-v1/me.png +``` + +Asset URLs Base Path +-------------------- + +When all assets are stored in a common path, use the `PathPackage` to avoid +repeating yourself: + +```php +use Symfony\Component\Asset\PathPackage; + +$package = new PathPackage('/images', 'v1'); + +echo $package->getUrl('/me.png'); +// /images/me.png?v1 +``` + +Asset URLs Base URLs +-------------------- + +If your assets are hosted on different domain name than the main website, use +the `UrlPackage` class: + +```php +use Symfony\Component\Asset\UrlPackage; + +$package = new UrlPackage('http://assets.example.com/images/', 'v1'); + +echo $package->getUrl('/me.png'); +// http://assets.example.com/images/me.png?v1 +``` + +One technique used to speed up page rendering in browsers is to use several +domains for assets; this is possible by passing more than one base URLs: ```php +use Symfony\Component\Asset\UrlPackage; + +$urls = array( + 'http://a1.example.com/images/', + 'http://a2.example.com/images/', +); +$package = new UrlPackage($urls, 'v1'); + +echo $package->getUrl('/me.png'); +// http://a1.example.com/images/me.png?v1 +``` + +Note that it's also guaranteed that any given path will always use the same +base URL to be nice with HTTP caching mechanisms. + +HttpFoundation Integration +-------------------------- + +If you are using HttpFoundation for your project, use the `RequestPathPackage` +and `RequestUrlPackage` classes alternatives to `PathPackage` and `UrlPackage`: + +```php +use Symfony\Component\Asset\RequestPathPackage; + +$package = new RequestPathPackage($requestStack, 'images', 'v1'); + +echo $package->getUrl('/me.png'); +// /somewhere/images/me.png?v1 +``` + +In addition to the configured base path, `RequestPathPackage` also +automatically prepends the current request base URL to assets to allow your +website to be hosted anywhere under the web server root directory. + +```php +use Symfony\Component\Asset\RequestUrlPackage; + +$package = new RequestUrlPackage($requestStack, array('http://example.com/', 'https://example.com/'), 'v1'); + +echo $package->getUrl('/me.png'); +// https://example.com/images/me.png?v1 +``` + +`RequestUrlPackage` uses the current request scheme (HTTP or HTTPs) to select +an appropriate base URL (HTTPs or protocol-relative URLs for HTTPs requests, +any base URL for HTTP requests). + +Named Packages +-------------- + +The `Packages` class allows to easily manages several packages in a single +project by naming packages: + +```php +use Symfony\Component\Asset\Package; +use Symfony\Component\Asset\PathPackage; +use Symfony\Component\Asset\UrlPackage; +use Symfony\Component\Asset\Packages; + +// by default, just add a version to all assets +$defaultPackage = new Asset\Package('v1'); + +$namedPackages = array( + // images are hosted on another web server + 'img' => new Asset\UrlPackage('http://img.example.com/', 'v1'), + + // documents are stored deeply under the web root directory + // let's create a shortcut + 'doc' => new Asset\PathPackage('/somewhere/deep/for/documents', 'v1'), +); + +// bundle all packages to make it easy to use them +$packages = new Asset\Packages($defaultPackage, $namedPackages); + +echo $packages->getUrl('/some.css'); +// /some.css?v1 + +echo $packages->getUrl('/me.png', 'img'); +// http://img.example.com/me.png?v1 + +echo $packages->getUrl('/me.pdf', 'doc'); +// /somewhere/deep/for/documents/me.pdf?v1 ``` Resources diff --git a/src/Symfony/Component/Asset/RequestPathPackage.php b/src/Symfony/Component/Asset/RequestPathPackage.php index 0b2478ecc310a..00d8880f92841 100644 --- a/src/Symfony/Component/Asset/RequestPathPackage.php +++ b/src/Symfony/Component/Asset/RequestPathPackage.php @@ -14,6 +14,15 @@ use Symfony\Component\HttpFoundation\RequestStack; /** + * Package that adds a base path to asset URLs in addition to a version. + * + * In addition to the provided base path, this package also automatically + * prepends the current request base path to allow a website to be hosted + * easily under any given path under the Web Server root directory. + * + * When no request is available, it falls back to only use the configured + * base path. + * * @author Fabien Potencier */ class RequestPathPackage extends PathPackage @@ -25,11 +34,11 @@ class RequestPathPackage extends PathPackage * @param string $version The version * @param string $format The version format */ - public function __construct(RequestStack $requestStack, $version = null, $format = null) + public function __construct(RequestStack $requestStack, $basePath = '', $version = null, $format = null) { $this->requestStack = $requestStack; - parent::__construct(null, $version, $format); + parent::__construct($basePath, $version, $format); } /** @@ -37,6 +46,10 @@ public function __construct(RequestStack $requestStack, $version = null, $format */ public function getBasePath() { - return $this->requestStack->getCurrentRequest()->getBasePath().'/'; + if (!$request = $this->requestStack->getCurrentRequest()) { + return parent::getBasePath(); + } + + return $request->getBasePath().parent::getBasePath(); } } diff --git a/src/Symfony/Component/Asset/RequestUrlPackage.php b/src/Symfony/Component/Asset/RequestUrlPackage.php index ff5ff1d66c083..3b297fb55467d 100644 --- a/src/Symfony/Component/Asset/RequestUrlPackage.php +++ b/src/Symfony/Component/Asset/RequestUrlPackage.php @@ -14,48 +14,50 @@ use Symfony\Component\HttpFoundation\RequestStack; /** + * Package that adds a base URL to asset URLs in addition to a version. + * + * As this package is aware of the current HTTP request, it can + * determine the best base URL to use based on the current request + * scheme. + * + * * For HTTP request, it chooses between all base URLs; + * * For HTTPs requests, it chooses between HTTPs base URLs and relative protocol URLs + * or falls back to any base URL if no secure ones are available. + * + * When no request is available, it falls back to choose between all base URLs. + * * @author Fabien Potencier */ -class RequestUrlPackage implements PackageInterface +class RequestUrlPackage extends UrlPackage { - private $version; private $requestStack; - private $package; private $sslPackage; /** * @param RequestStack $request The request stack + * @param string|array $baseUrls Base asset URLs * @param string $version The version * @param string $format The version format */ public function __construct(RequestStack $requestStack, $baseUrls = array(), $version = null, $format = null) { $this->requestStack = $requestStack; - $this->version = $version; - - list($allUrls, $sslUrls) = $this->organizeUrls($baseUrls); - if (!$allUrls) { - $this->package = new RequestPathPackage($requestStack, $version, $format); - } elseif ($allUrls === $sslUrls) { - $this->package = new UrlPackage($allUrls, $version, $format); - } else { - $this->package = new UrlPackage($allUrls, $version, $format); + if (!is_array($baseUrls)) { + $baseUrls = (array) $baseUrls; + } - if ($sslUrls) { - $this->sslPackage = new UrlPackage($sslUrls, $version, $format); - } else { - $this->sslPackage = new RequestPathPackage($version, $format); - } + if (!$baseUrls) { + throw new \LogicException('You must provide at least one base URL.'); } - } - /** - * {@inheritdoc} - */ - public function getVersion() - { - return $this->version; + $sslUrls = $this->getSslUrls($baseUrls); + + parent::__construct($baseUrls, $version, $format); + + if ($sslUrls && $baseUrls !== $sslUrls) { + $this->sslPackage = new UrlPackage($sslUrls, $version, $format); + } } /** @@ -64,31 +66,27 @@ public function getVersion() public function getUrl($path, $version = null) { if (null === $this->sslPackage) { - return $this->package->getUrl($path, $version); + return parent::getUrl($path, $version); } if (($request = $this->requestStack->getCurrentRequest()) && $request->isSecure()) { return $this->sslPackage->getUrl($path, $version); } - return $this->package->getUrl($path, $version); + return parent::getUrl($path, $version); } - private function organizeUrls($urls) + private function getSslUrls($urls) { - $sslUrls = isset($urls['ssl']) ? $urls['ssl'] : array(); - $allUrls = array_merge(isset($urls['http']) ? $urls['http'] : array(), $sslUrls); - foreach ($urls as $i => $url) { - if (!is_integer($i)) { - continue; - } - - $allUrls[] = $url; - if (0 === strpos($url, 'https://') || 0 === strpos($url, '//')) { + $sslUrls = array(); + foreach ($urls as $url) { + if ('https://' === substr($url, 0, 8) || '//' === substr($url, 0, 2)) { $sslUrls[] = $url; + } elseif ('http://' !== substr($url, 0, 7)) { + throw new \InvalidArgumentException(sprintf('"%s" is not a valid URL', $url)); } } - return array($allUrls, $sslUrls); + return $sslUrls; } } diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php index 54645d370ba12..0ce541d732a5a 100644 --- a/src/Symfony/Component/Asset/UrlPackage.php +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -12,7 +12,12 @@ namespace Symfony\Component\Asset; /** - * The URL packages adds a version and a base URL to asset URLs. + * Package that adds a base URL to asset URLs in addition to a version. + * + * The package allows to use more than one base URLs in which case + * it randomly chooses one for each asset; it also guarantees that + * any given path will always use the same base URL to be nice with + * HTTP caching mechanisms. * * @author Kris Wallsmith */ @@ -35,6 +40,10 @@ public function __construct($baseUrls = array(), $version = null, $format = null $baseUrls = (array) $baseUrls; } + if (!$baseUrls) { + throw new \LogicException('You must provide at least one base URL.'); + } + $this->baseUrls = array(); foreach ($baseUrls as $baseUrl) { $this->baseUrls[] = rtrim($baseUrl, '/'); @@ -46,7 +55,7 @@ public function __construct($baseUrls = array(), $version = null, $format = null */ public function getUrl($path, $version = null) { - if (false !== strpos($path, '://') || 0 === strpos($path, '//')) { + if ($this->isAbsoluteUrl($path)) { return $path; } @@ -69,9 +78,6 @@ public function getUrl($path, $version = null) public function getBaseUrl($path) { switch ($count = count($this->baseUrls)) { - case 0: - return ''; - case 1: return $this->baseUrls[0]; From 686bee62cb33133ab9bba2d9637d6eec63f0342f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 3 Jan 2015 20:43:30 +0100 Subject: [PATCH 13/13] [Asset] added some tests --- .../Component/Asset/Tests/PackageTest.php | 58 ++++++++++++++++ .../Component/Asset/Tests/PackagesTest.php | 68 ++++++++++++++++++ .../Component/Asset/Tests/PathPackageTest.php | 54 +++++++++++++++ .../Asset/Tests/RequestPathPackageTest.php | 63 +++++++++++++++++ .../Asset/Tests/RequestUrlPathPackageTest.php | 69 +++++++++++++++++++ .../Component/Asset/Tests/UrlPackageTest.php | 64 +++++++++++++++++ src/Symfony/Component/Asset/composer.json | 6 ++ 7 files changed, 382 insertions(+) create mode 100644 src/Symfony/Component/Asset/Tests/PackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/PackagesTest.php create mode 100644 src/Symfony/Component/Asset/Tests/PathPackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/RequestPathPackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/RequestUrlPathPackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/UrlPackageTest.php diff --git a/src/Symfony/Component/Asset/Tests/PackageTest.php b/src/Symfony/Component/Asset/Tests/PackageTest.php new file mode 100644 index 0000000000000..81384f1e1b98c --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PackageTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\Package; + +class PackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($version, $format, $path, $expected) + { + $package = new Package($version, $format); + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getConfigs() + { + return array( + array('v1', '', 'http://example.com/foo', 'http://example.com/foo'), + array('v1', '', 'https://example.com/foo', 'https://example.com/foo'), + array('v1', '', '//example.com/foo', '//example.com/foo'), + + array('v1', '', '/foo', '/foo?v1'), + array('v1', '', 'foo', 'foo?v1'), + + array('', '', '/foo', '/foo'), + array('', '', 'foo', 'foo'), + + array('v1', 'version-%2$s/%1$s', '/foo', '/version-v1/foo'), + array('v1', 'version-%2$s/%1$s', 'foo', 'version-v1/foo'), + array('v1', 'version-%2$s/%1$s', 'foo/', 'version-v1/foo/'), + array('v1', 'version-%2$s/%1$s', '/foo/', '/version-v1/foo/'), + ); + } + + public function testGetUrlWithSpecificVersion() + { + $package = new Package('v1'); + $this->assertEquals('/foo?v2', $package->getUrl('/foo', 'v2')); + } + + public function testGetVersion() + { + $package = new Package('v1'); + $this->assertEquals('v1', $package->getVersion()); + } +} diff --git a/src/Symfony/Component/Asset/Tests/PackagesTest.php b/src/Symfony/Component/Asset/Tests/PackagesTest.php new file mode 100644 index 0000000000000..f973d40e4af49 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PackagesTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\Package; +use Symfony\Component\Asset\Packages; + +class PackagesTest extends \PHPUnit_Framework_TestCase +{ + public function testGetterSetters() + { + $packages = new Packages(); + $packages->setDefaultPackage($default = $this->getMock('Symfony\Component\Asset\PackageInterface')); + $packages->addPackage('a', $a = $this->getMock('Symfony\Component\Asset\PackageInterface')); + + $this->assertEquals($default, $packages->getPackage()); + $this->assertEquals($a, $packages->getPackage('a')); + + $packages = new Packages($default, array('a' => $a)); + + $this->assertEquals($default, $packages->getPackage()); + $this->assertEquals($a, $packages->getPackage('a')); + } + + public function testGetVersion() + { + $packages = new Packages(new Package('default'), array('a' => new Package('a'))); + + $this->assertEquals('default', $packages->getVersion()); + $this->assertEquals('a', $packages->getVersion('a')); + } + + public function testGetUrl() + { + $packages = new Packages(new Package('default'), array('a' => new Package('a'))); + + $this->assertEquals('/foo?default', $packages->getUrl('/foo')); + $this->assertEquals('/foo?a', $packages->getUrl('/foo', 'a')); + $this->assertEquals('/foo?v1', $packages->getUrl('/foo', null, 'v1')); + } + + /** + * @expectedException \LogicException + */ + public function testNoDefaultPackage() + { + $packages = new Packages(); + $packages->getPackage(); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUndefinedPackage() + { + $packages = new Packages(); + $packages->getPackage('a'); + } +} diff --git a/src/Symfony/Component/Asset/Tests/PathPackageTest.php b/src/Symfony/Component/Asset/Tests/PathPackageTest.php new file mode 100644 index 0000000000000..aeb578df44f9d --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PathPackageTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\PathPackage; + +class PathPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($basePath, $format, $path, $expected) + { + $package = new PathPackage($basePath, 'v1', $format); + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getConfigs() + { + return array( + array('/foo', '', 'http://example.com/foo', 'http://example.com/foo'), + array('/foo', '', 'https://example.com/foo', 'https://example.com/foo'), + array('/foo', '', '//example.com/foo', '//example.com/foo'), + + array('', '', '/foo', '/foo?v1'), + + array('/foo', '', '/foo', '/foo?v1'), + array('/foo', '', 'foo', '/foo/foo?v1'), + array('foo', '', 'foo', '/foo/foo?v1'), + array('foo/', '', 'foo', '/foo/foo?v1'), + array('/foo/', '', 'foo', '/foo/foo?v1'), + + array('/foo', 'version-%2$s/%1$s', '/foo', '/version-v1/foo'), + array('/foo', 'version-%2$s/%1$s', 'foo', '/foo/version-v1/foo'), + array('/foo', 'version-%2$s/%1$s', 'foo/', '/foo/version-v1/foo/'), + array('/foo', 'version-%2$s/%1$s', '/foo/', '/version-v1/foo/'), + ); + } + + public function testGetUrlWithSpecificVersion() + { + $package = new PathPackage('v1'); + $this->assertEquals('/foo?v2', $package->getUrl('/foo', 'v2')); + } +} diff --git a/src/Symfony/Component/Asset/Tests/RequestPathPackageTest.php b/src/Symfony/Component/Asset/Tests/RequestPathPackageTest.php new file mode 100644 index 0000000000000..903425c046ef9 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/RequestPathPackageTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\RequestPathPackage; + +class RequestPathPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($basePathRequest, $basePath, $format, $path, $expected) + { + $package = new RequestPathPackage($this->getRequestStack($basePathRequest), $basePath, 'v1', $format); + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getConfigs() + { + return array( + array('', '/foo', '', '/foo', '/foo?v1'), + array('', '/foo', '', 'foo', '/foo/foo?v1'), + array('', 'foo', '', 'foo', '/foo/foo?v1'), + array('', 'foo/', '', 'foo', '/foo/foo?v1'), + array('', '/foo/', '', 'foo', '/foo/foo?v1'), + + array('/bar', '/foo', '', '/foo', '/foo?v1'), + array('/bar', '/foo', '', 'foo', '/bar/foo/foo?v1'), + array('/bar', 'foo', '', 'foo', '/bar/foo/foo?v1'), + array('/bar', 'foo/', '', 'foo', '/bar/foo/foo?v1'), + array('/bar', '/foo/', '', 'foo', '/bar/foo/foo?v1'), + + array(false, '/foo/', '', 'foo', '/foo/foo?v1'), + ); + } + + private function getRequestStack($basePath) + { + $stack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack'); + + if (false === $basePath) { + $stack->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(null)); + + return $stack; + } + + $request = $this->getMock('Symfony\Component\HttpFoundation\Request'); + $request->expects($this->any())->method('getBasePath')->will($this->returnValue($basePath)); + + $stack->expects($this->any())->method('getCurrentRequest')->will($this->returnValue($request)); + + return $stack; + } +} diff --git a/src/Symfony/Component/Asset/Tests/RequestUrlPathPackageTest.php b/src/Symfony/Component/Asset/Tests/RequestUrlPathPackageTest.php new file mode 100644 index 0000000000000..d01879e84b015 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/RequestUrlPathPackageTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\RequestUrlPackage; + +class RequestUrlPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($secure, $basePath, $format, $path, $expected) + { + $package = new RequestUrlPackage($this->getRequestStack($secure), $basePath, 'v1', $format); + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getConfigs() + { + return array( + array(false, 'http://example.com', '', 'foo', 'http://example.com/foo?v1'), + array(false, array('http://example.com'), '', 'foo', 'http://example.com/foo?v1'), + array(false, array('http://example.com', 'https://example.com'), '', 'foo', 'http://example.com/foo?v1'), + array(false, array('http://example.com', 'https://example.com'), '', 'fooa', 'https://example.com/fooa?v1'), + array(false, array('http://example.com/bar'), '', 'foo', 'http://example.com/bar/foo?v1'), + array(false, array('http://example.com/bar/'), '', 'foo', 'http://example.com/bar/foo?v1'), + array(false, array('//example.com/bar/'), '', 'foo', '//example.com/bar/foo?v1'), + + array(true, array('http://example.com'), '', 'foo', 'http://example.com/foo?v1'), + array(true, array('http://example.com', 'https://example.com'), '', 'foo', 'https://example.com/foo?v1'), + ); + } + + /** + * @expectedException \LogicException + */ + public function testNoBaseUrls() + { + new RequestUrlPackage($this->getRequestStack(false), array()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testWrongBaseUrl() + { + new RequestUrlPackage($this->getRequestStack(false), array('not-a-url')); + } + + private function getRequestStack($secure) + { + $request = $this->getMock('Symfony\Component\HttpFoundation\Request'); + $request->expects($this->any())->method('isSecure')->will($this->returnValue($secure)); + + $stack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack'); + $stack->expects($this->any())->method('getCurrentRequest')->will($this->returnValue($request)); + + return $stack; + } +} diff --git a/src/Symfony/Component/Asset/Tests/UrlPackageTest.php b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php new file mode 100644 index 0000000000000..880d8a9af50d8 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Tests; + +use Symfony\Component\Asset\UrlPackage; + +class UrlPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($baseUrls, $format, $path, $expected) + { + $package = new UrlPackage($baseUrls, 'v1', $format); + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getConfigs() + { + return array( + array('http://example.net', '', 'http://example.com/foo', 'http://example.com/foo'), + array('http://example.net', '', 'https://example.com/foo', 'https://example.com/foo'), + array('http://example.net', '', '//example.com/foo', '//example.com/foo'), + + array('http://example.com', '', '/foo', 'http://example.com/foo?v1'), + array('http://example.com', '', 'foo', 'http://example.com/foo?v1'), + array('http://example.com/', '', 'foo', 'http://example.com/foo?v1'), + array('http://example.com/foo', '', 'foo', 'http://example.com/foo/foo?v1'), + array('http://example.com/foo/', '', 'foo', 'http://example.com/foo/foo?v1'), + + array(array('http://example.com'), '', '/foo', 'http://example.com/foo?v1'), + array(array('http://example.com', 'http://example.net'), '', '/foo', 'http://example.com/foo?v1'), + array(array('http://example.com', 'http://example.net'), '', '/fooa', 'http://example.net/fooa?v1'), + + array('http://example.com', 'version-%2$s/%1$s', '/foo', 'http://example.com/version-v1/foo'), + array('http://example.com', 'version-%2$s/%1$s', 'foo', 'http://example.com/version-v1/foo'), + array('http://example.com', 'version-%2$s/%1$s', 'foo/', 'http://example.com/version-v1/foo/'), + array('http://example.com', 'version-%2$s/%1$s', '/foo/', 'http://example.com/version-v1/foo/'), + ); + } + + public function testGetUrlWithSpecificVersion() + { + $package = new UrlPackage('http://example.com'); + $this->assertEquals('http://example.com/foo?v2', $package->getUrl('/foo', 'v2')); + } + + /** + * @expectedException \LogicException + */ + public function testNoBaseUrls() + { + new UrlPackage(array(), 'v1'); + } +} diff --git a/src/Symfony/Component/Asset/composer.json b/src/Symfony/Component/Asset/composer.json index f7b16eff7500d..2f73863ff2678 100644 --- a/src/Symfony/Component/Asset/composer.json +++ b/src/Symfony/Component/Asset/composer.json @@ -18,6 +18,12 @@ "require": { "php": ">=5.3.3" }, + "suggest": { + "symfony/http-foundation": "" + }, + "require-dev": { + "symfony/http-foundation": "~2.4" + }, "autoload": { "psr-0": { "Symfony\\Component\\Asset\\": "" } },