diff --git a/composer.json b/composer.json index b123e37c78..5a04094969 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "psr/log": "~1.0" }, "replace": { + "symfony/asset": "self.version", "symfony/browser-kit": "self.version", "symfony/class-loader": "self.version", "symfony/config": "self.version", diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 887e9acf34..9781390321 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * added LogoutUrlExtension (provides `logout_url` and `logout_path`) * added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions) + * added AssetExtension (provides the `asset` and `asset_version` functions) 2.5.0 ----- diff --git a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php new file mode 100644 index 0000000000..3e9e9f6a78 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\Asset\Packages; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + +/** + * Twig extension for the Symfony Asset component. + * + * @author Fabien Potencier + */ +class AssetExtension extends \Twig_Extension +{ + private $packages; + private $foundationExtension; + + /** + * Passing an HttpFoundationExtension instance as a second argument must not be relied on + * as it's only there to maintain BC with older Symfony version. It will be removed in 3.0. + */ + public function __construct(Packages $packages, HttpFoundationExtension $foundationExtension = null) + { + $this->packages = $packages; + $this->foundationExtension = $foundationExtension; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('asset', array($this, 'getAssetUrl')), + new \Twig_SimpleFunction('asset_version', array($this, 'getAssetVersion')), + new \Twig_SimpleFunction('assets_version', array($this, 'getAssetsVersion')), + ); + } + + /** + * Returns the public url/path of an asset. + * + * If the package used to generate the path is an instance of + * UrlPackage, you will always get a URL and not a path. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * + * @return string The public path of the asset + */ + public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null) + { + // BC layer to be removed in 3.0 + if (2 < $count = func_num_args()) { + trigger_error('Generating absolute URLs with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0. Please use absolute_url() instead.', E_USER_DEPRECATED); + if (4 === $count) { + trigger_error('Forcing a version with the Twig asset() function was deprecated in 2.7 and will be removed in 3.0.', E_USER_DEPRECATED); + } + + $args = func_get_args(); + + return $this->getLegacyAssetUrl($path, $packageName, $args[2], isset($args[3]) ? $args[3] : null); + } + + return $this->packages->getUrl($path, $packageName); + } + + /** + * Returns the version of an asset. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * + * @return string The asset version + */ + public function getAssetVersion($path, $packageName = null) + { + return $this->packages->getVersion($path, $packageName); + } + + public function getAssetsVersion($packageName = null) + { + trigger_error('The Twig assets_version() function was deprecated in 2.7 and will be removed in 3.0. Please use asset_version() instead.', E_USER_DEPRECATED); + + return $this->packages->getVersion('/', $packageName); + } + + private function getLegacyAssetUrl($path, $packageName = null, $absolute = false, $version = null) + { + if ($version) { + $package = $this->packages->getPackage($packageName); + + $v = new \ReflectionProperty($package, 'versionStrategy'); + $v->setAccessible(true); + + $currentVersionStrategy = $v->getValue($package); + + $f = new \ReflectionProperty($currentVersionStrategy, 'format'); + $f->setAccessible(true); + $format = $f->getValue($currentVersionStrategy); + + $v->setValue($package, new StaticVersionStrategy($version, $format)); + } + + try { + $url = $this->packages->getUrl($path, $packageName); + } catch (\Exception $e) { + if ($version) { + $v->setValue($package, $currentVersionStrategy); + } + + throw $e; + } + + if ($version) { + $v->setValue($package, $currentVersionStrategy); + } + + if ($absolute) { + return $this->foundationExtension->generateAbsoluteUrl($url); + } + + return $url; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'asset'; + } +} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AssetExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AssetExtensionTest.php new file mode 100644 index 0000000000..4c67f4fd19 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AssetExtensionTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\AssetExtension; +use Symfony\Component\Asset\Package; +use Symfony\Component\Asset\Packages; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + +class AssetExtensionTest extends \PHPUnit_Framework_TestCase +{ + public function testLegacyGetAssetUrl() + { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + + $foundationExtension = $this->getMockBuilder('Symfony\Bridge\Twig\Extension\HttpFoundationExtension')->disableOriginalConstructor()->getMock(); + $foundationExtension + ->expects($this->any()) + ->method('generateAbsoluteUrl') + ->will($this->returnCallback(function ($arg) { return 'http://localhost/'.$arg; })) + ; + + $package = new Package(new StaticVersionStrategy('22', '%s?version=%s')); + $packages = new Packages($package); + $extension = new AssetExtension($packages, $foundationExtension); + + $this->assertEquals('me.png?version=42', $extension->getAssetUrl('me.png', null, false, '42')); + $this->assertEquals('http://localhost/me.png?version=22', $extension->getAssetUrl('me.png', null, true)); + $this->assertEquals('http://localhost/me.png?version=42', $extension->getAssetUrl('me.png', null, true, '42')); + } +} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index c534b8f6ac..df8a513113 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/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index 39a4e13bbd..5e59391e9c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -16,6 +16,11 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; +trigger_error('The '.__NAMESPACE__.'\TemplatingAssetHelperPass class is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED); + +/** + * @deprecated since 2.7, will be removed in 3.0 + */ class TemplatingAssetHelperPass implements CompilerPassInterface { public function process(ContainerBuilder $container) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 105326112c..95aa34c50e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -53,6 +53,44 @@ class Configuration implements ConfigurationInterface return $v; }) ->end() + ->validate() + ->ifTrue(function ($v) { return isset($v['templating']); }) + ->then(function ($v) { + if ($v['templating']['assets_version'] + || count($v['templating']['assets_base_urls']['http']) + || count($v['templating']['assets_base_urls']['ssl']) + || count($v['templating']['packages']) + ) { + trigger_error('The assets settings under framework.templating are deprecated since version 2.7 and will be removed in 3.0. Use the framework.assets configuration key instead', E_USER_DEPRECATED); + + // convert the old configuration to the new one + if (isset($v['assets'])) { + throw new LogicException('You cannot use assets settings under "templating.templating" and "assets" configurations in the same project.'); + } + + $v['assets'] = array( + 'version' => $v['templating']['assets_version'], + 'version_format' => $v['templating']['assets_version_format'], + 'base_path' => '', + 'base_urls' => array_values(array_unique(array_merge($v['templating']['assets_base_urls']['http'], $v['templating']['assets_base_urls']['ssl']))), + 'packages' => array(), + ); + + foreach ($v['templating']['packages'] as $name => $config) { + $v['assets']['packages'][$name] = array( + 'version' => (string) $config['version'], + 'version_format' => $config['version_format'], + 'base_path' => '', + 'base_urls' => array_values(array_unique(array_merge($config['base_urls']['http'], $config['base_urls']['ssl']))), + ); + } + } + + unset($v['templating']['assets_version'], $v['templating']['assets_version_format'], $v['templating']['assets_base_urls'], $v['templating']['packages']); + + return $v; + }) + ->end() ->children() ->scalarNode('secret')->end() ->scalarNode('http_method_override') @@ -108,6 +146,7 @@ class Configuration implements ConfigurationInterface $this->addSessionSection($rootNode); $this->addRequestSection($rootNode); $this->addTemplatingSection($rootNode); + $this->addAssetsSection($rootNode); $this->addTranslatorSection($rootNode); $this->addValidationSection($rootNode); $this->addAnnotationsSection($rootNode); @@ -347,8 +386,8 @@ class Configuration implements ConfigurationInterface ->info('templating configuration') ->canBeUnset() ->children() - ->scalarNode('assets_version')->defaultValue(null)->end() - ->scalarNode('assets_version_format')->defaultValue('%%s?%%s')->end() + ->scalarNode('assets_version')->defaultNull()->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')->end() + ->scalarNode('assets_version_format')->defaultValue('%%s?%%s')->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.')->end() ->scalarNode('hinclude_default_template')->defaultNull()->end() ->arrayNode('form') ->addDefaultsIfNotSet() @@ -370,6 +409,7 @@ class Configuration implements ConfigurationInterface ->fixXmlConfig('assets_base_url') ->children() ->arrayNode('assets_base_urls') + ->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.') ->performNoDeepMerging() ->addDefaultsIfNotSet() ->beforeNormalization() @@ -417,6 +457,7 @@ class Configuration implements ConfigurationInterface ->fixXmlConfig('package') ->children() ->arrayNode('packages') + ->info('Deprecated since 2.7, will be removed in 3.0. Use the new assets entry instead.') ->useAttributeAsKey('name') ->prototype('array') ->fixXmlConfig('base_url') @@ -452,6 +493,54 @@ class Configuration implements ConfigurationInterface ; } + private function addAssetsSection(ArrayNodeDefinition $rootNode) + { + $rootNode + ->children() + ->arrayNode('assets') + ->info('assets configuration') + ->canBeUnset() + ->fixXmlConfig('base_url') + ->children() + ->scalarNode('version')->defaultNull()->end() + ->scalarNode('version_format')->defaultValue('%%s?%%s')->end() + ->scalarNode('base_path')->defaultValue('')->end() + ->arrayNode('base_urls') + ->requiresAtLeastOneElement() + ->beforeNormalization() + ->ifTrue(function ($v) { return !is_array($v); }) + ->then(function ($v) { return array($v); }) + ->end() + ->prototype('scalar')->end() + ->end() + ->end() + ->fixXmlConfig('package') + ->children() + ->arrayNode('packages') + ->useAttributeAsKey('name') + ->prototype('array') + ->fixXmlConfig('base_url') + ->children() + ->scalarNode('version')->defaultNull()->end() + ->scalarNode('version_format')->defaultNull()->end() + ->scalarNode('base_path')->defaultValue('')->end() + ->arrayNode('base_urls') + ->requiresAtLeastOneElement() + ->beforeNormalization() + ->ifTrue(function ($v) { return !is_array($v); }) + ->then(function ($v) { return array($v); }) + ->end() + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ; + } + private function addTranslatorSection(ArrayNodeDefinition $rootNode) { $rootNode diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1a38962f16..bbd824e1d1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -49,6 +49,7 @@ class FrameworkExtension extends Extension $loader->load('web.xml'); $loader->load('services.xml'); $loader->load('fragment_renderer.xml'); + $loader->load('assets.xml'); // A translator must always be registered (as support is included by // default in the Form component). If disabled, an identity translator @@ -101,6 +102,10 @@ class FrameworkExtension extends Extension $this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader); + if (isset($config['assets'])) { + $this->registerAssetsConfiguration($config['assets'], $container, $loader); + } + if (isset($config['templating'])) { $this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader); } @@ -469,23 +474,6 @@ class FrameworkExtension extends Extension $container->setParameter('templating.helper.code.file_link_format', isset($links[$ide]) ? $links[$ide] : $ide); $container->setParameter('fragment.renderer.hinclude.global_template', $config['hinclude_default_template']); - $loader->load('old_assets.xml'); - - // create package definitions and add them to the assets helper - $defaultPackage = $this->createTemplatingPackageDefinition($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->createTemplatingPackageDefinition($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')) { $logger = new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE); @@ -565,71 +553,81 @@ class FrameworkExtension extends Extension } } + /** + * Loads the assets configuration. + * + * @param array $config A assets configuration array + * @param ContainerBuilder $container A ContainerBuilder instance + * @param XmlFileLoader $loader An XmlFileLoader instance + */ + private function registerAssetsConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) + { + $defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], '_default'); + + $defaultPackage = $this->createPackageDefinition($config['base_path'], $config['base_urls'], $defaultVersion); + $container->setDefinition('assets._default_package', $defaultPackage); + + $namedPackages = array(); + foreach ($config['packages'] as $name => $package) { + if (null === $package['version']) { + $version = $defaultVersion; + } else { + $format = $package['version_format'] ?: $config['version_format']; + $version = $this->createVersion($container, $package['version'], $format, $name); + } + + $container->setDefinition('assets._package_'.$name, $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version)); + $namedPackages[$name] = new Reference('assets._package_'.$name); + } + + $container->getDefinition('assets.packages') + ->replaceArgument(0, new Reference('assets._default_package')) + ->replaceArgument(1, $namedPackages) + ; + } + /** * Returns a definition for an asset package. */ - private function createTemplatingPackageDefinition(ContainerBuilder $container, array $httpUrls, array $sslUrls, $version, $format, $name = null) + private function createPackageDefinition($basePath, array $baseUrls, Reference $version) { - if (!$httpUrls) { - $package = new DefinitionDecorator('templating.asset.path_package'); - $package + if ($basePath && $baseUrls) { + throw new \LogicException('An asset package cannot have base URLs and base paths.'); + } + + if (!$baseUrls) { + $package = new DefinitionDecorator('assets.path_package'); + + return $package ->setPublic(false) - ->setScope('request') + ->replaceArgument(0, $basePath) ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; - - return $package; - } - - if ($httpUrls == $sslUrls) { - $package = new DefinitionDecorator('templating.asset.url_package'); - $package - ->setPublic(false) - ->replaceArgument(0, $sslUrls) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; - - return $package; - } - - $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) - ; - $container->setDefinition($prefix.'.http', $httpPackage); - - if ($sslUrls) { - $sslPackage = new DefinitionDecorator('templating.asset.url_package'); - $sslPackage - ->replaceArgument(0, $sslUrls) - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) - ; - } else { - $sslPackage = new DefinitionDecorator('templating.asset.path_package'); - $sslPackage - ->setScope('request') - ->replaceArgument(1, $version) - ->replaceArgument(2, $format) ; } - $container->setDefinition($prefix.'.ssl', $sslPackage); - $package = new DefinitionDecorator('templating.asset.request_aware_package'); - $package + $package = new DefinitionDecorator('assets.url_package'); + + return $package ->setPublic(false) - ->setScope('request') - ->replaceArgument(1, $prefix.'.http') - ->replaceArgument(2, $prefix.'.ssl') + ->replaceArgument(0, $baseUrls) + ->replaceArgument(1, $version) ; + } - return $package; + private function createVersion(ContainerBuilder $container, $version, $format, $name) + { + if (null === $version) { + return new Reference('assets.empty_version_strategy'); + } + + $def = new DefinitionDecorator('assets.static_version_strategy'); + $def + ->replaceArgument(0, $version) + ->replaceArgument(1, $format) + ; + $container->setDefinition('assets._version_'.$name, $def); + + return new Reference('assets._version_'.$name); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 5ddc397560..499f39c6c9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -16,7 +16,6 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInit 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\TemplatingAssetHelperPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass; @@ -76,7 +75,6 @@ class FrameworkBundle extends Bundle // but as late as possible to get resolved parameters $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); - $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 new file mode 100644 index 0000000000..4f2e1fbf36 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index cc3cd1de47..652d168a77 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -18,6 +18,7 @@ + @@ -125,12 +126,34 @@ + + + + + + + + + + + + + + + + + + + + + + - + @@ -146,7 +169,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml index efec555b87..59da78fc41 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml @@ -14,7 +14,6 @@ Symfony\Component\Templating\Loader\CacheLoader Symfony\Component\Templating\Loader\ChainLoader Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinder - Symfony\Component\Templating\Helper\CoreAssetsHelper @@ -59,15 +58,5 @@ - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml index 5b4f8073fe..556206d43b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml @@ -15,6 +15,7 @@ Symfony\Bundle\FrameworkBundle\Templating\Helper\TranslatorHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\StopwatchHelper + Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper Symfony\Component\Form\Extension\Templating\TemplatingRendererEngine Symfony\Component\Form\FormRenderer Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables @@ -65,6 +66,12 @@ + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php index 0a63a29cd6..ef76796a26 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\PackageFactory is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\Asset\PackageInterface; @@ -19,6 +21,8 @@ use Symfony\Component\Templating\Asset\PackageInterface; * Creates packages based on whether the current request is secure. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ class PackageFactory { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php index 6aa8c58824..e75e25106b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php @@ -14,10 +14,14 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Asset; 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 the Asset component 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 the Asset component instead. */ class PathPackage extends BasePathPackage { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/AssetsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/AssetsHelper.php new file mode 100644 index 0000000000..dcbb6bfe56 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/AssetsHelper.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Templating\Helper; + +use Symfony\Component\Asset\Packages; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; +use Symfony\Component\Templating\Helper\Helper; + +/** + * AssetsHelper helps manage asset URLs. + * + * @author Fabien Potencier + */ +class AssetsHelper extends Helper +{ + private $packages; + + public function __construct(Packages $packages) + { + $this->packages = $packages; + } + + /** + * Returns the public url/path of an asset. + * + * If the package used to generate the path is an instance of + * UrlPackage, you will always get a URL and not a path. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * + * @return string The public path of the asset + */ + public function getUrl($path, $packageName = null, $version = null) + { + // BC layer to be removed in 3.0 + if (3 === $count = func_num_args()) { + trigger_error('Forcing a version for an asset was deprecated in 2.7 and will be removed in 3.0.', E_USER_DEPRECATED); + + $args = func_get_args(); + + return $this->getLegacyAssetUrl($path, $packageName, $args[2]); + } + + return $this->packages->getUrl($path, $packageName); + } + + /** + * Returns the version of an asset. + * + * @param string $path A public path + * @param string $packageName The name of the asset package to use + * + * @return string The asset version + */ + public function getVersion($path = null, $packageName = null) + { + // no arguments means old getVersion() for default package + if (null === $path) { + trigger_error('The getVersion() method requires a path as a first argument since 2.7 and will be enforced as of 3.0.', E_USER_DEPRECATED); + + return $this->packages->getVersion('/', $packageName); + } + + // path and packageName can only be for the new version + if (null !== $packageName) { + return $this->packages->getVersion($path, $packageName); + } + + // packageName is null and path not, so path is a path or a packageName + try { + $package = $this->packages->getPackage($path); + } catch (\InvalidArgumentException $e) { + // path is not a package, so it should be a path + return $this->packages->getVersion($path); + } + + // path is a packageName, old version + trigger_error('The getVersion() method requires a path as a first argument since 2.7 and will be enforced as of 3.0.', E_USER_DEPRECATED); + + return $this->packages->getVersion('/', $path); + } + + private function getLegacyAssetUrl($path, $packageName = null, $version = null) + { + if ($version) { + $package = $this->packages->getPackage($packageName); + + $v = new \ReflectionProperty($package, 'versionStrategy'); + $v->setAccessible(true); + + $currentVersionStrategy = $v->getValue($package); + + $f = new \ReflectionProperty($currentVersionStrategy, 'format'); + $f->setAccessible(true); + $format = $f->getValue($currentVersionStrategy); + + $v->setValue($package, new StaticVersionStrategy($version, $format)); + } + + $url = $this->packages->getUrl($path, $packageName); + + if ($version) { + $v->setValue($package, $currentVersionStrategy); + } + + return $url; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'assets'; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LegacyTemplatingAssetHelperPassTest.php similarity index 98% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LegacyTemplatingAssetHelperPassTest.php index 3a096715e1..10a6e08568 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TemplatingAssetHelperPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LegacyTemplatingAssetHelperPassTest.php @@ -16,7 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; -class TemplatingAssetHelperPassTest extends \PHPUnit_Framework_TestCase +class LegacyTemplatingAssetHelperPassTest extends \PHPUnit_Framework_TestCase { public function getScopesTests() { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php new file mode 100644 index 0000000000..e3532a7747 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php @@ -0,0 +1,25 @@ +loadFromExtension('framework', array( + 'assets' => array( + 'version' => 'SomeVersionScheme', + 'base_urls' => 'http://cdn.example.com', + 'version_format' => '%%s?version=%%s', + 'packages' => array( + 'images_path' => array( + 'base_path' => '/foo', + ), + 'images' => array( + 'version' => '1.0.0', + 'base_urls' => array('http://images1.example.com', 'http://images2.example.com'), + ), + 'foo' => array( + 'version' => '1.0.0', + 'version_format' => '%%s-%%s', + ), + 'bar' => array( + 'base_urls' => array('https://bar2.example.com'), + ), + ), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php index ab356dafd7..679da4161d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -39,23 +39,9 @@ $container->loadFromExtension('framework', array( 'save_path' => '/path/to/sessions', ), 'templating' => array( - 'assets_version' => 'SomeVersionScheme', - 'assets_base_urls' => 'http://cdn.example.com', 'cache' => '/path/to/cache', 'engines' => array('php', 'twig'), 'loader' => array('loader.foo', 'loader.bar'), - 'packages' => array( - 'images' => array( - 'version' => '1.0.0', - 'base_urls' => array('http://images1.example.com', 'http://images2.example.com'), - ), - 'foo' => array( - 'version' => '1.0.0', - ), - 'bar' => array( - 'base_urls' => array('http://bar1.example.com', 'http://bar2.example.com'), - ), - ), 'form' => array( 'resources' => array('theme1', 'theme2'), ), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_assets.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_assets.php new file mode 100644 index 0000000000..32bd56b358 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_assets.php @@ -0,0 +1,23 @@ +loadFromExtension('framework', array( + 'templating' => array( + 'engines' => array('php'), + 'assets_version' => 'SomeVersionScheme', + 'assets_base_urls' => 'http://cdn.example.com', + 'assets_version_format' => '%%s?version=%%s', + 'packages' => array( + 'images' => array( + 'version' => '1.0.0', + 'base_urls' => array('http://images1.example.com', 'http://images2.example.com'), + ), + 'foo' => array( + 'version' => '1.0.0', + 'version_format' => '%%s-%%s', + ), + 'bar' => array( + 'base_urls' => array('https://bar2.example.com'), + ), + ), + ), +)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_url_package.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_url_package.php similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating_url_package.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_url_package.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml new file mode 100644 index 0000000000..e39e15f900 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml @@ -0,0 +1,23 @@ + + + + + + + http://cdn.example.com + + + http://images1.example.com + http://images2.example.com + + + + https://bar2.example.com + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 024cef66cc..4f41288410 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -24,21 +24,11 @@ application/pdf - + loader.foo loader.bar php twig - http://cdn.example.com - - http://images1.example.com - http://images2.example.com - - - - http://bar1.example.com - http://bar2.example.com - theme1 theme2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_assets.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_assets.xml new file mode 100644 index 0000000000..963848f767 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_assets.xml @@ -0,0 +1,23 @@ + + + + + + + php + http://cdn.example.com + + http://images1.example.com + http://images2.example.com + + + + https://bar2.example.com + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/templating_url_package.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_url_package.xml similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/templating_url_package.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_url_package.xml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml new file mode 100644 index 0000000000..193dc59dfb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml @@ -0,0 +1,16 @@ +framework: + assets: + version: SomeVersionScheme + version_format: %%s?version=%%s + base_urls: http://cdn.example.com + packages: + images_path: + base_path: '/foo' + images: + version: 1.0.0 + base_urls: ["http://images1.example.com", "http://images2.example.com"] + foo: + version: 1.0.0 + version_format: %%s-%%s + bar: + base_urls: ["https://bar2.example.com"] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index d16f24c4ca..3fd70b7eba 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -30,19 +30,9 @@ framework: gc_maxlifetime: 90000 save_path: /path/to/sessions templating: - assets_version: SomeVersionScheme - assets_base_urls: http://cdn.example.com engines: [php, twig] loader: [loader.foo, loader.bar] cache: /path/to/cache - packages: - images: - version: 1.0.0 - base_urls: ["http://images1.example.com", "http://images2.example.com"] - foo: - version: 1.0.0 - bar: - base_urls: ["http://images1.example.com", "http://images2.example.com"] form: resources: [theme1, theme2] hinclude_default_template: global_hinclude_template diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_assets.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_assets.yml new file mode 100644 index 0000000000..e8cc6ce41d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_assets.yml @@ -0,0 +1,15 @@ +framework: + templating: + engines: [php] + assets_version: SomeVersionScheme + assets_version_format: %%s?version=%%s + assets_base_urls: http://cdn.example.com + packages: + images: + version: 1.0.0 + base_urls: ["http://images1.example.com", "http://images2.example.com"] + foo: + version: 1.0.0 + version_format: %%s-%%s + bar: + base_urls: "https://bar2.example.com" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_url_package.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_url_package.yml similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/templating_url_package.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_url_package.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 8e112baf2a..344065d623 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -14,6 +14,8 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Validator\Validation; @@ -186,21 +188,6 @@ abstract class FrameworkExtensionTest extends TestCase $this->assertTrue($container->hasDefinition('templating.name_parser'), '->registerTemplatingConfiguration() loads templating.xml'); - // default package should have one HTTP base URL and path package SSL URL - $this->assertTrue($container->hasDefinition('templating.asset.default_package.http')); - $package = $container->getDefinition('templating.asset.default_package.http'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\DefinitionDecorator', $package); - $this->assertEquals('templating.asset.url_package', $package->getParent()); - $arguments = array_values($package->getArguments()); - $this->assertEquals(array('http://cdn.example.com'), $arguments[0]); - $this->assertEquals('SomeVersionScheme', $arguments[1]); - $this->assertEquals('%%s?%%s', $arguments[2]); - - $this->assertTrue($container->hasDefinition('templating.asset.default_package.ssl')); - $package = $container->getDefinition('templating.asset.default_package.ssl'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\DefinitionDecorator', $package); - $this->assertEquals('templating.asset.path_package', $package->getParent()); - $this->assertEquals('templating.engine.delegating', (string) $container->getAlias('templating'), '->registerTemplatingConfiguration() configures delegating loader if multiple engines are provided'); $this->assertEquals($container->getDefinition('templating.loader.chain'), $container->getDefinition('templating.loader.wrapped'), '->registerTemplatingConfiguration() configures loader chain if multiple loaders are provided'); @@ -216,11 +203,16 @@ abstract class FrameworkExtensionTest extends TestCase $this->assertEquals('global_hinclude_template', $container->getParameter('fragment.renderer.hinclude.global_template'), '->registerTemplatingConfiguration() registers the global hinclude.js template'); } - public function testTemplatingAssetsHelperScopeDependsOnPackageArgumentScopes() + public function testLegacyTemplatingAssets() { - $container = $this->createContainerFromFile('templating_url_package'); + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); - $this->assertNotEquals('request', $container->getDefinition('templating.helper.assets')->getScope(), '->registerTemplatingConfiguration() does not set request scope on assets helper if no packages are request-scoped'); + $this->checkAssetsPackages($this->createContainerFromFile('legacy_templating_assets'), true); + } + + public function testAssets() + { + $this->checkAssetsPackages($this->createContainerFromFile('assets')); } public function testTranslator() @@ -528,4 +520,71 @@ abstract class FrameworkExtensionTest extends TestCase return $container; } + + protected function createContainerFromClosure($closure, $data = array()) + { + $container = $this->createContainer($data); + $container->registerExtension(new FrameworkExtension()); + $loader = new ClosureLoader($container); + $loader->load($closure); + + $container->getCompilerPassConfig()->setOptimizationPasses(array()); + $container->getCompilerPassConfig()->setRemovingPasses(array()); + $container->compile(); + + return $container; + } + + private function checkAssetsPackages(ContainerBuilder $container, $legacy = false) + { + $packages = $container->getDefinition('assets.packages'); + + // default package + $defaultPackage = $container->getDefinition($packages->getArgument(0)); + $this->assertUrlPackage($container, $defaultPackage, array('http://cdn.example.com'), 'SomeVersionScheme', '%%s?version=%%s'); + + // packages + $packages = $packages->getArgument(1); + $this->assertCount($legacy ? 3 : 4, $packages); + + if (!$legacy) { + $package = $container->getDefinition($packages['images_path']); + $this->assertPathPackage($container, $package, '/foo', 'SomeVersionScheme', '%%s?version=%%s'); + } + + $package = $container->getDefinition($packages['images']); + $this->assertUrlPackage($container, $package, array('http://images1.example.com', 'http://images2.example.com'), '1.0.0', $legacy ? '%%s?%%s' : '%%s?version=%%s'); + + $package = $container->getDefinition($packages['foo']); + $this->assertPathPackage($container, $package, '', '1.0.0', '%%s-%%s'); + + $package = $container->getDefinition($packages['bar']); + $this->assertUrlPackage($container, $package, array('https://bar2.example.com'), $legacy ? '' : 'SomeVersionScheme', $legacy ? '%%s?%%s' : '%%s?version=%%s'); + } + + private function assertPathPackage(ContainerBuilder $container, Definition $package, $basePath, $version, $format) + { + $this->assertEquals('assets.path_package', $package->getParent()); + $this->assertEquals($basePath, $package->getArgument(0)); + $this->assertVersionStrategy($container, $package->getArgument(1), $version, $format); + } + + private function assertUrlPackage(ContainerBuilder $container, Definition $package, $baseUrls, $version, $format) + { + $this->assertEquals('assets.url_package', $package->getParent()); + $this->assertEquals($baseUrls, $package->getArgument(0)); + $this->assertVersionStrategy($container, $package->getArgument(1), $version, $format); + } + + private function assertVersionStrategy(ContainerBuilder $container, Reference $reference, $version, $format) + { + $versionStrategy = $container->getDefinition($reference); + if (null === $version) { + $this->assertEquals('assets.empty_version_strategy', (string) $reference); + } else { + $this->assertEquals('assets.static_version_strategy', $versionStrategy->getParent()); + $this->assertEquals($version, $versionStrategy->getArgument(0)); + $this->assertEquals($format, $versionStrategy->getArgument(1)); + } + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php index fad373e471..01c73930db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -22,4 +22,38 @@ class PhpFrameworkExtensionTest extends FrameworkExtensionTest $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/Fixtures/php')); $loader->load($file.'.php'); } + + /** + * @expectedException \LogicException + */ + public function testAssetsCannotHavePathAndUrl() + { + $container = $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', array( + 'assets' => array( + 'base_urls' => 'http://cdn.example.com', + 'base_path' => '/foo', + ), + )); + }); + } + + /** + * @expectedException \LogicException + */ + public function testAssetPackageCannotHavePathAndUrl() + { + $container = $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', array( + 'assets' => array( + 'packages' => array( + 'impossible' => array( + 'base_urls' => 'http://cdn.example.com', + 'base_path' => '/foo', + ), + ), + ), + )); + }); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/AssetsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/AssetsHelper.php new file mode 100644 index 0000000000..7ef641d756 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/AssetsHelper.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Templating\Helper; + +use Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper; +use Symfony\Component\Asset\Package; +use Symfony\Component\Asset\Packages; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + +class AssetsHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testLegacyGetUrl() + { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + + $package = new Package(new StaticVersionStrategy('22', '%s?version=%s')); + $packages = new Packages($package); + $helper = new AssetsHelper($packages); + + $this->assertEquals('me.png?version=42', $helper->getUrl('me.png', null, '42')); + } + + public function testLegacyGetVersion() + { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + + $package = new Package(new StaticVersionStrategy('22')); + $imagePackage = new Package(new StaticVersionStrategy('42')); + $packages = new Packages($package, array('images' => $imagePackage)); + $helper = new AssetsHelper($packages); + + $this->assertEquals('22', $helper->getVersion()); + $this->assertEquals('22', $helper->getVersion('/foo')); + $this->assertEquals('42', $helper->getVersion('images')); + $this->assertEquals('42', $helper->getVersion('/foo', 'images')); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index dce63a74b9..6d57657ef1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -32,6 +32,7 @@ "doctrine/annotations": "~1.0" }, "require-dev": { + "symfony/asset": "~2.7|~3.0.0", "symfony/browser-kit": "~2.4|~3.0.0", "symfony/console": "~2.6|~3.0.0", "symfony/css-selector": "~2.0,>=2.0.5|~3.0.0", @@ -47,6 +48,7 @@ "symfony/yaml": "~2.0,>=2.0.5|~3.0.0" }, "suggest": { + "symfony/asset": "", "symfony/console": "For using the console commands", "symfony/finder": "For using the translation loader and cache warmer", "symfony/form": "For using forms", diff --git a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md index afd8f8177f..82325777bc 100644 --- a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +2.7.0 +----- + + * added support for the new Asset component (from Twig bridge) + * deprecated the assets extension (use the one from the Twig bridge instead) + 2.6.0 ----- diff --git a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php index d596f97e52..9d03aa7079 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php @@ -14,10 +14,14 @@ namespace Symfony\Bundle\TwigBundle\Extension; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Routing\RequestContext; +trigger_error('The '.__NAMESPACE__.'\AssetsExtension class is deprecated since version 2.7 and will be removed in 3.0. Use the Symfony\Bridge\Twig\Extension\AssetExtension class instead.', E_USER_DEPRECATED); + /** * Twig extension for Symfony assets helper. * * @author Fabien Potencier + * + * @deprecated since 2.7, to be removed in 3.0. Use Symfony\Component\Twig\Extension\AssetExtension 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 8f6002d47e..83bb14735d 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -11,7 +11,6 @@ Symfony\Bundle\TwigBundle\TwigEngine Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheCacheWarmer Symfony\Bridge\Twig\Extension\TranslationExtension - Symfony\Bundle\TwigBundle\Extension\AssetsExtension Symfony\Bundle\TwigBundle\Extension\ActionsExtension Symfony\Bridge\Twig\Extension\CodeExtension Symfony\Bridge\Twig\Extension\RoutingExtension @@ -86,10 +85,10 @@ - + - - + + diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception_full.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception_full.html.twig index f97c60b9e4..24d437d45e 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception_full.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/exception_full.html.twig @@ -1,7 +1,7 @@ {% extends 'TwigBundle::layout.html.twig' %} {% block head %} - + {% endblock %} {% block title %} diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/layout.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/layout.html.twig index 75cf109048..ef59ed5408 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/layout.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/layout.html.twig @@ -4,8 +4,8 @@ {% block title %}{% endblock %} - - + + {% block head %}{% endblock %} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Extension/AssetsExtensionTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Extension/LegacyAssetsExtensionTest.php similarity index 98% rename from src/Symfony/Bundle/TwigBundle/Tests/Extension/AssetsExtensionTest.php rename to src/Symfony/Bundle/TwigBundle/Tests/Extension/LegacyAssetsExtensionTest.php index eddf7adcc0..425349942f 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Extension/AssetsExtensionTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Extension/LegacyAssetsExtensionTest.php @@ -15,7 +15,7 @@ use Symfony\Bundle\TwigBundle\Extension\AssetsExtension; use Symfony\Bundle\TwigBundle\Tests\TestCase; use Symfony\Component\Routing\RequestContext; -class AssetsExtensionTest extends TestCase +class LegacyAssetsExtensionTest extends TestCase { /** * @dataProvider provideGetGetAssetUrlArguments diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php index f1992bbe9f..132315fd23 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php @@ -52,9 +52,6 @@ class WebProfilerExtensionTest extends TestCase $this->container->addScope(new Scope('request')); $this->container->register('request', 'Symfony\\Component\\HttpFoundation\\Request')->setScope('request'); $this->container->register('router', $this->getMockClass('Symfony\\Component\\Routing\\RouterInterface')); - $this->container->register('templating.helper.assets', $this->getMockClass('Symfony\\Component\\Templating\\Helper\\AssetsHelper')); - $this->container->register('templating.helper.router', $this->getMockClass('Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\RouterHelper')) - ->addArgument(new Reference('router')); $this->container->register('twig', 'Twig_Environment'); $this->container->setParameter('kernel.bundles', array()); $this->container->setParameter('kernel.cache_dir', __DIR__); diff --git a/src/Symfony/Component/Asset/.gitignore b/src/Symfony/Component/Asset/.gitignore new file mode 100644 index 0000000000..c49a5d8df5 --- /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 0000000000..619a423402 --- /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/Context/ContextInterface.php b/src/Symfony/Component/Asset/Context/ContextInterface.php new file mode 100644 index 0000000000..83282021ae --- /dev/null +++ b/src/Symfony/Component/Asset/Context/ContextInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Context; + +/** + * Holds information about the current request. + * + * @author Fabien Potencier + */ +interface ContextInterface +{ + /** + * Gets the base path. + * + * @return string The base path + */ + public function getBasePath(); + + /** + * Checks whether the request is secure or not. + * + * @return bool true if the request is secure, false otherwise + */ + public function isSecure(); +} diff --git a/src/Symfony/Component/Asset/Context/NullContext.php b/src/Symfony/Component/Asset/Context/NullContext.php new file mode 100644 index 0000000000..47d29d7d2e --- /dev/null +++ b/src/Symfony/Component/Asset/Context/NullContext.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Context; + +use Symfony\Component\HttpFoundation\RequestStack; + +/** + * A context that does nothing. + * + * @author Fabien Potencier + */ +class NullContext implements ContextInterface +{ + /** + * {@inheritdoc} + */ + public function getBasePath() + { + return ''; + } + + /** + * {@inheritdoc} + */ + public function isSecure() + { + return false; + } +} diff --git a/src/Symfony/Component/Asset/Context/RequestStackContext.php b/src/Symfony/Component/Asset/Context/RequestStackContext.php new file mode 100644 index 0000000000..ba7113851d --- /dev/null +++ b/src/Symfony/Component/Asset/Context/RequestStackContext.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Context; + +use Symfony\Component\HttpFoundation\RequestStack; + +/** + * Uses a RequestStack to populate the context. + * + * @author Fabien Potencier + */ +class RequestStackContext implements ContextInterface +{ + private $requestStack; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public function getBasePath() + { + if (!$request = $this->requestStack->getMasterRequest()) { + return ''; + } + + return $request->getBasePath(); + } + + /** + * {@inheritdoc} + */ + public function isSecure() + { + if (!$request = $this->requestStack->getMasterRequest()) { + return false; + } + + return $request->isSecure(); + } +} diff --git a/src/Symfony/Component/Asset/Exception/ExceptionInterface.php b/src/Symfony/Component/Asset/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..cce1b5cced --- /dev/null +++ b/src/Symfony/Component/Asset/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Exception; + +/** + * Base ExceptionInterface for the Asset component. + * + * @author Fabien Potencier + */ +interface ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Asset/Exception/InvalidArgumentException.php b/src/Symfony/Component/Asset/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..0945d8fad1 --- /dev/null +++ b/src/Symfony/Component/Asset/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Exception; + +/** + * Base InvalidArgumentException for the Asset component. + * + * @author Fabien Potencier + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Asset/Exception/LogicException.php b/src/Symfony/Component/Asset/Exception/LogicException.php new file mode 100644 index 0000000000..f291d88d52 --- /dev/null +++ b/src/Symfony/Component/Asset/Exception/LogicException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\Exception; + +/** + * Base LogicException for the Asset component. + * + * @author Fabien Potencier + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Asset/LICENSE b/src/Symfony/Component/Asset/LICENSE new file mode 100644 index 0000000000..43028bc600 --- /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 0000000000..43bdcf21db --- /dev/null +++ b/src/Symfony/Component/Asset/Package.php @@ -0,0 +1,72 @@ + + * + * 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\Asset\Context\ContextInterface; +use Symfony\Component\Asset\Context\NullContext; +use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; + +/** + * Basic package that adds a version to asset URLs. + * + * @author Kris Wallsmith + * @author Fabien Potencier + */ +class Package implements PackageInterface +{ + private $versionStrategy; + private $context; + + public function __construct(VersionStrategyInterface $versionStrategy, ContextInterface $context = null) + { + $this->versionStrategy = $versionStrategy; + $this->context = $context ?: new NullContext(); + } + + /** + * {@inheritdoc} + */ + public function getVersion($path) + { + return $this->versionStrategy->getVersion($path); + } + + /** + * {@inheritdoc} + */ + public function getUrl($path) + { + if ($this->isAbsoluteUrl($path)) { + return $path; + } + + return $this->versionStrategy->applyVersion($path); + } + + /** + * @return ContextInterface + */ + protected function getContext() + { + return $this->context; + } + + protected function getVersionStrategy() + { + return $this->versionStrategy; + } + + protected function isAbsoluteUrl($url) + { + return false !== strpos($url, '://') || '//' === substr($url, 0, 2); + } +} diff --git a/src/Symfony/Component/Asset/PackageInterface.php b/src/Symfony/Component/Asset/PackageInterface.php new file mode 100644 index 0000000000..b9e9ff90b9 --- /dev/null +++ b/src/Symfony/Component/Asset/PackageInterface.php @@ -0,0 +1,38 @@ + + * + * 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 version for an asset. + * + * @param string $path A path + * + * @return string The version string + */ + public function getVersion($path); + + /** + * Returns an absolute or root-relative public path. + * + * @param string $path A path + * + * @return string The public path + */ + public function getUrl($path); +} diff --git a/src/Symfony/Component/Asset/Packages.php b/src/Symfony/Component/Asset/Packages.php new file mode 100644 index 0000000000..e980b7608e --- /dev/null +++ b/src/Symfony/Component/Asset/Packages.php @@ -0,0 +1,116 @@ + + * + * 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\Asset\Exception\InvalidArgumentException; +use Symfony\Component\Asset\Exception\LogicException; + +/** + * 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 = null, 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 + * @throws LogicException If no default package is defined + */ + 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; + } + + 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 $path A public path + * @param string $packageName A package name + * + * @return string The current version + */ + public function getVersion($path, $packageName = null) + { + return $this->getPackage($packageName)->getVersion($path); + } + + /** + * 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 + * + * @return string A public path which takes into account the base path and URL path + */ + public function getUrl($path, $packageName = null) + { + return $this->getPackage($packageName)->getUrl($path); + } +} diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php new file mode 100644 index 0000000000..906879f8b0 --- /dev/null +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -0,0 +1,71 @@ + + * + * 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\Asset\Context\ContextInterface; +use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; + +/** + * 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 if a Context is available to + * allow a website to be hosted easily under any given path under the Web + * Server root directory. + * + * @author Fabien Potencier + */ +class PathPackage extends Package +{ + private $basePath; + + /** + * @param string $basePath The base path to be prepended to relative paths + * @param VersionStrategyInterface $versionStrategy The version strategy + */ + public function __construct($basePath, VersionStrategyInterface $versionStrategy, ContextInterface $context = null) + { + parent::__construct($versionStrategy, $context); + + if (!$basePath) { + $this->basePath = '/'; + } else { + if ('/' != $basePath[0]) { + $basePath = '/'.$basePath; + } + + $this->basePath = rtrim($basePath, '/').'/'; + } + } + + /** + * {@inheritdoc} + */ + public function getUrl($path) + { + if ($this->isAbsoluteUrl($path)) { + return $path; + } + + return $this->getBasePath().ltrim($this->getVersionStrategy()->applyVersion($path), '/'); + } + + /** + * Returns the base path. + * + * @return string The base path + */ + public function getBasePath() + { + return $this->getContext()->getBasePath().$this->basePath; + } +} diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md new file mode 100644 index 0000000000..f2e66b832e --- /dev/null +++ b/src/Symfony/Component/Asset/README.md @@ -0,0 +1,166 @@ +Asset Component +=============== + +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; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + +$package = new Package(new StaticVersionStrategy('v1')); + +echo $package->getUrl('/me.png'); +// /me.png?v1 +``` + +The default format can be configured: + +```php +$package = new Package(new StaticVersionStrategy('v1', '%s?version=%s')); + +echo $package->getUrl('/me.png'); +// /me.png?version=v1 + +// put the version before the path +$package = new Package(new StaticVersionStrategy('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', new StaticVersionStrategy('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/', new StaticVersionStrategy('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, new StaticVersionStrategy('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, set the Context to get +additional features for free: + +```php +use Symfony\Component\Asset\PathPackage; +use Symfony\Component\Asset\Context\RequestStackContext; + +$package = new PathPackage('images', new StaticVersionStrategy('v1')); +$package->setContext(new RequestStackContext($requestStack)); + +echo $package->getUrl('/me.png'); +// /somewhere/images/me.png?v1 +``` + +In addition to the configured base path, `PathPackage` now 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\UrlPackage; +use Symfony\Component\Asset\Context\RequestStackContext; + +$package = new UrlPackage(array('http://example.com/', 'https://example.com/'), new StaticVersionStrategy('v1')); +$package->setContext(new RequestStackContext($requestStack)); + +echo $package->getUrl('/me.png'); +// https://example.com/images/me.png?v1 +``` + +`UrlPackage` now 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 +$versionStrategy = new StaticVersionStrategy('v1'); +$defaultPackage = new Asset\Package($versionStrategy); + +$namedPackages = array( + // images are hosted on another web server + 'img' => new Asset\UrlPackage('http://img.example.com/', $versionStrategy), + + // documents are stored deeply under the web root directory + // let's create a shortcut + 'doc' => new Asset\PathPackage('/somewhere/deep/for/documents', $versionStrategy), +); + +// 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 +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Asset/ + $ composer update + $ phpunit diff --git a/src/Symfony/Component/Asset/Tests/PackageTest.php b/src/Symfony/Component/Asset/Tests/PackageTest.php new file mode 100644 index 0000000000..a2310d5898 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PackageTest.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\Package; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; +use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy; + +class PackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($version, $format, $path, $expected) + { + $package = new Package($version ? new StaticVersionStrategy($version, $format) : new EmptyVersionStrategy()); + $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(null, '', '/foo', '/foo'), + array(null, '', '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 testGetVersion() + { + $package = new Package(new StaticVersionStrategy('v1')); + $this->assertEquals('v1', $package->getVersion('/foo')); + } +} diff --git a/src/Symfony/Component/Asset/Tests/PackagesTest.php b/src/Symfony/Component/Asset/Tests/PackagesTest.php new file mode 100644 index 0000000000..81db37b996 --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PackagesTest.php @@ -0,0 +1,76 @@ + + * + * 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; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; +use Symfony\Component\Asset\Exception\InvalidArgumentException; +use Symfony\Component\Asset\Exception\LogicException; + +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(new StaticVersionStrategy('default')), + array('a' => new Package(new StaticVersionStrategy('a'))) + ); + + $this->assertEquals('default', $packages->getVersion('/foo')); + $this->assertEquals('a', $packages->getVersion('/foo', 'a')); + } + + public function testGetUrl() + { + $packages = new Packages( + new Package(new StaticVersionStrategy('default')), + array('a' => new Package(new StaticVersionStrategy('a'))) + ); + + $this->assertEquals('/foo?default', $packages->getUrl('/foo')); + $this->assertEquals('/foo?a', $packages->getUrl('/foo', 'a')); + } + + /** + * @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 0000000000..ff5b0a052f --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/PathPackageTest.php @@ -0,0 +1,84 @@ + + * + * 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; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + +class PathPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($basePath, $format, $path, $expected) + { + $package = new PathPackage($basePath, new StaticVersionStrategy('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/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', '/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/', '/foo/version-v1/foo/'), + ); + } + + /** + * @dataProvider getContextConfigs + */ + public function testGetUrlWithContext($basePathRequest, $basePath, $format, $path, $expected) + { + $package = new PathPackage($basePath, new StaticVersionStrategy('v1', $format), $this->getContext($basePathRequest)); + + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getContextConfigs() + { + return array( + 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/', '', '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('/bar', '/foo/', '', 'foo', '/bar/foo/foo?v1'), + ); + } + + private function getContext($basePath) + { + $context = $this->getMock('Symfony\Component\Asset\Context\ContextInterface'); + $context->expects($this->any())->method('getBasePath')->will($this->returnValue($basePath)); + + return $context; + } +} diff --git a/src/Symfony/Component/Asset/Tests/UrlPackageTest.php b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php new file mode 100644 index 0000000000..515bd926ea --- /dev/null +++ b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php @@ -0,0 +1,104 @@ + + * + * 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; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; +use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy; +use Symfony\Component\Asset\Exception\InvalidArgumentException; +use Symfony\Component\Asset\Exception\LogicException; + +class UrlPackageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getConfigs + */ + public function testGetUrl($baseUrls, $format, $path, $expected) + { + $package = new UrlPackage($baseUrls, new StaticVersionStrategy('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/'), + ); + } + + /** + * @dataProvider getContextConfigs + */ + public function testGetUrlWithContext($secure, $baseUrls, $format, $path, $expected) + { + $package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format), $this->getContext($secure)); + + $this->assertEquals($expected, $package->getUrl($path)); + } + + public function getContextConfigs() + { + 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 UrlPackage(array(), new EmptyVersionStrategy()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testWrongBaseUrl() + { + new UrlPackage(array('not-a-url'), new EmptyVersionStrategy()); + } + + private function getContext($secure) + { + $context = $this->getMock('Symfony\Component\Asset\Context\ContextInterface'); + $context->expects($this->any())->method('isSecure')->will($this->returnValue($secure)); + + return $context; + } +} diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php new file mode 100644 index 0000000000..0e9f82d0fa --- /dev/null +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -0,0 +1,135 @@ + + * + * 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\Asset\Context\ContextInterface; +use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; +use Symfony\Component\Asset\Exception\InvalidArgumentException; +use Symfony\Component\Asset\Exception\LogicException; + +/** + * 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. + * + * When the request context is available, this package can choose 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. + * + * @author Fabien Potencier + */ +class UrlPackage extends Package +{ + private $baseUrls = array(); + private $sslUrls; + private $sslPackage; + + /** + * @param string|array $baseUrls Base asset URLs + * @param VersionStrategyInterface $versionStrategy The version strategy + */ + public function __construct($baseUrls = array(), VersionStrategyInterface $versionStrategy, ContextInterface $context = null) + { + parent::__construct($versionStrategy, $context); + + if (!is_array($baseUrls)) { + $baseUrls = (array) $baseUrls; + } + + if (!$baseUrls) { + throw new LogicException('You must provide at least one base URL.'); + } + + foreach ($baseUrls as $baseUrl) { + $this->baseUrls[] = rtrim($baseUrl, '/'); + } + + $sslUrls = $this->getSslUrls($baseUrls); + + if ($sslUrls && $baseUrls !== $sslUrls) { + $this->sslPackage = new UrlPackage($sslUrls, $versionStrategy); + } + } + + /** + * {@inheritdoc} + */ + public function getUrl($path) + { + if ($this->isAbsoluteUrl($path)) { + return $path; + } + + if (null !== $this->sslPackage && $this->getContext()->isSecure()) { + return $this->sslPackage->getUrl($path); + } + + $url = $this->getVersionStrategy()->applyVersion($path); + + 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) + { + if (1 === count($this->baseUrls)) { + return $this->baseUrls[0]; + } + + return $this->baseUrls[$this->chooseBaseUrl($path)]; + } + + /** + * Determines which base URL to use for the given path. + * + * Override this method to change the default distribution strategy. + * This method should always return the same base URL for a given path. + * + * @param string $path + * + * @return string The base URL for the given path + */ + protected function chooseBaseUrl($path) + { + return fmod(hexdec(substr(hash('sha256', $path), 0, 10)), count($this->baseUrls)); + } + + private function getSslUrls($urls) + { + $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 $sslUrls; + } +} diff --git a/src/Symfony/Component/Asset/VersionStrategy/EmptyVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/EmptyVersionStrategy.php new file mode 100644 index 0000000000..aa06eaa55e --- /dev/null +++ b/src/Symfony/Component/Asset/VersionStrategy/EmptyVersionStrategy.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\VersionStrategy; + +/** + * Disable version for all assets. + * + * @author Fabien Potencier + */ +class EmptyVersionStrategy implements VersionStrategyInterface +{ + /** + * {@inheritdoc} + */ + public function getVersion($path) + { + return ''; + } + + /** + * {@inheritdoc} + */ + public function applyVersion($path) + { + return $path; + } +} diff --git a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php new file mode 100644 index 0000000000..6028eb57fe --- /dev/null +++ b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\VersionStrategy; + +/** + * Returns the same version for all assets. + * + * @author Fabien Potencier + */ +class StaticVersionStrategy implements VersionStrategyInterface +{ + private $version; + private $format; + + public function __construct($version, $format = null) + { + $this->version = $version; + $this->format = $format ?: '%s?%s'; + } + + /** + * {@inheritdoc} + */ + public function getVersion($path) + { + return $this->version; + } + + /** + * {@inheritdoc} + */ + public function applyVersion($path) + { + $versionized = sprintf($this->format, ltrim($path, '/'), $this->getVersion($path)); + + if ($path && '/' == $path[0]) { + return '/'.$versionized; + } + + return $versionized; + } +} diff --git a/src/Symfony/Component/Asset/VersionStrategy/VersionStrategyInterface.php b/src/Symfony/Component/Asset/VersionStrategy/VersionStrategyInterface.php new file mode 100644 index 0000000000..a0fb260033 --- /dev/null +++ b/src/Symfony/Component/Asset/VersionStrategy/VersionStrategyInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Asset\VersionStrategy; + +/** + * Asset version strategy interface. + * + * @author Fabien Potencier + */ +interface VersionStrategyInterface +{ + /** + * Returns the asset version for an asset. + * + * @param string $path A path + * + * @return string The version string + */ + public function getVersion($path); + + /** + * Applies version to the supplied path. + * + * @param string $path A path + * + * @return string The versionized path + */ + public function applyVersion($path); +} diff --git a/src/Symfony/Component/Asset/composer.json b/src/Symfony/Component/Asset/composer.json new file mode 100644 index 0000000000..cf058bb3b2 --- /dev/null +++ b/src/Symfony/Component/Asset/composer.json @@ -0,0 +1,36 @@ +{ + "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" + }, + "suggest": { + "symfony/http-foundation": "" + }, + "require-dev": { + "symfony/http-foundation": "~2.4" + }, + "autoload": { + "psr-4": { "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 0000000000..547ecdaa7a --- /dev/null +++ b/src/Symfony/Component/Asset/phpunit.xml.dist @@ -0,0 +1,24 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./vendor + ./Tests + + + + diff --git a/src/Symfony/Component/Templating/Asset/Package.php b/src/Symfony/Component/Templating/Asset/Package.php index 02a1269bd9..cfc33ccbcf 100644 --- a/src/Symfony/Component/Templating/Asset/Package.php +++ b/src/Symfony/Component/Templating/Asset/Package.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Templating\Asset; +trigger_error('The Symfony\Component\Templating\Asset\Package is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + /** * The basic package will add a version to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ class Package implements PackageInterface { diff --git a/src/Symfony/Component/Templating/Asset/PackageInterface.php b/src/Symfony/Component/Templating/Asset/PackageInterface.php index 7317b555ac..f19f6fc3c4 100644 --- a/src/Symfony/Component/Templating/Asset/PackageInterface.php +++ b/src/Symfony/Component/Templating/Asset/PackageInterface.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Templating\Asset; +trigger_error('The Symfony\Component\Templating\Asset\PackageInterface is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + /** * Asset package interface. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ interface PackageInterface { diff --git a/src/Symfony/Component/Templating/Asset/PathPackage.php b/src/Symfony/Component/Templating/Asset/PathPackage.php index 1806107f6d..48f69523df 100644 --- a/src/Symfony/Component/Templating/Asset/PathPackage.php +++ b/src/Symfony/Component/Templating/Asset/PathPackage.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Templating\Asset; +trigger_error('The Symfony\Component\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component 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 the Asset component instead. */ class PathPackage extends Package { diff --git a/src/Symfony/Component/Templating/Asset/UrlPackage.php b/src/Symfony/Component/Templating/Asset/UrlPackage.php index 00a21670f4..2ab1d0f9d5 100644 --- a/src/Symfony/Component/Templating/Asset/UrlPackage.php +++ b/src/Symfony/Component/Templating/Asset/UrlPackage.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Templating\Asset; +trigger_error('The Symfony\Component\Templating\Asset\UrlPackage is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + /** * The URL packages adds a version and a base URL to asset URLs. * * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ class UrlPackage extends Package { diff --git a/src/Symfony/Component/Templating/Helper/AssetsHelper.php b/src/Symfony/Component/Templating/Helper/AssetsHelper.php index 128843ef0d..aceff61b61 100644 --- a/src/Symfony/Component/Templating/Helper/AssetsHelper.php +++ b/src/Symfony/Component/Templating/Helper/AssetsHelper.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Templating\Helper; +trigger_error('The Symfony\Component\Templating\Helper\AssetsHelper is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + use Symfony\Component\Templating\Asset\PathPackage; use Symfony\Component\Templating\Asset\UrlPackage; @@ -25,6 +27,8 @@ use Symfony\Component\Templating\Asset\UrlPackage; * * @author Fabien Potencier * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ class AssetsHelper extends CoreAssetsHelper { diff --git a/src/Symfony/Component/Templating/Helper/CoreAssetsHelper.php b/src/Symfony/Component/Templating/Helper/CoreAssetsHelper.php index b2d06a3362..41076a1bfb 100644 --- a/src/Symfony/Component/Templating/Helper/CoreAssetsHelper.php +++ b/src/Symfony/Component/Templating/Helper/CoreAssetsHelper.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Templating\Helper; +trigger_error('The Symfony\Component\Templating\Helper\CoreAssetsHelper is deprecated since version 2.7 and will be removed in 3.0. Use the Asset component instead.', E_USER_DEPRECATED); + use Symfony\Component\Templating\Asset\PackageInterface; /** @@ -24,6 +26,8 @@ use Symfony\Component\Templating\Asset\PackageInterface; * * @author Fabien Potencier * @author Kris Wallsmith + * + * @deprecated since 2.7, will be removed in 3.0. Use the Asset component instead. */ class CoreAssetsHelper extends Helper implements PackageInterface { diff --git a/src/Symfony/Component/Templating/Tests/Helper/AssetsHelperTest.php b/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php similarity index 95% rename from src/Symfony/Component/Templating/Tests/Helper/AssetsHelperTest.php rename to src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php index c29c6de1a3..a3e61fb975 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/AssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php @@ -13,8 +13,13 @@ namespace Symfony\Component\Templating\Tests\Helper; use Symfony\Component\Templating\Helper\AssetsHelper; -class AssetsHelperTest extends \PHPUnit_Framework_TestCase +class LegacyAssetsHelperTest extends \PHPUnit_Framework_TestCase { + public function setUp() + { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + } + public function testGetVersion() { $helper = new AssetsHelper(null, array(), 'foo'); diff --git a/src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php similarity index 89% rename from src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php rename to src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php index b681e9fab6..65695ee6eb 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php @@ -13,12 +13,14 @@ namespace Symfony\Component\Templating\Tests\Helper; use Symfony\Component\Templating\Helper\CoreAssetsHelper; -class CoreAssetsHelperTest extends \PHPUnit_Framework_TestCase +class LegacyCoreAssetsHelperTest extends \PHPUnit_Framework_TestCase { protected $package; protected function setUp() { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + $this->package = $this->getMock('Symfony\Component\Templating\Asset\PackageInterface'); }