From d33c41d43663f1f638ec083fa2b8c3bddec5ad1a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 28 Dec 2014 19:57:17 +0100 Subject: [PATCH 1/4] [Asset] added the component --- composer.json | 1 + src/Symfony/Bridge/Twig/CHANGELOG.md | 1 + .../Bridge/Twig/Extension/AssetExtension.php | 79 +++++++++ src/Symfony/Bridge/Twig/composer.json | 1 + .../Compiler/TemplatingAssetHelperPass.php | 3 + .../DependencyInjection/Configuration.php | 55 +++++- .../FrameworkExtension.php | 84 +++++++++ .../Resources/config/assets.xml | 42 +++++ .../Templating/Asset/PackageFactory.php | 4 + .../Templating/Asset/PathPackage.php | 4 + .../Bundle/FrameworkBundle/composer.json | 1 + src/Symfony/Bundle/TwigBundle/CHANGELOG.md | 6 + .../Compiler/ExtensionPass.php | 4 + .../TwigBundle/Extension/AssetsExtension.php | 6 + .../TwigBundle/Resources/config/twig.xml | 4 + ...Test.php => LegacyAssetsExtensionTest.php} | 2 +- src/Symfony/Component/Asset/.gitignore | 3 + src/Symfony/Component/Asset/CHANGELOG.md | 7 + .../Asset/Context/ContextInterface.php | 34 ++++ .../Asset/Context/RequestStackContext.php | 53 ++++++ .../Asset/Exception/ExceptionInterface.php | 21 +++ .../Exception/InvalidArgumentException.php | 21 +++ .../Asset/Exception/LogicException.php | 21 +++ src/Symfony/Component/Asset/LICENSE | 19 ++ src/Symfony/Component/Asset/Package.php | 75 ++++++++ .../Component/Asset/PackageInterface.php | 38 ++++ src/Symfony/Component/Asset/Packages.php | 116 ++++++++++++ src/Symfony/Component/Asset/PathPackage.php | 74 ++++++++ src/Symfony/Component/Asset/README.md | 166 ++++++++++++++++++ .../Component/Asset/Tests/PackageTest.php | 54 ++++++ .../Component/Asset/Tests/PackagesTest.php | 76 ++++++++ .../Component/Asset/Tests/PathPackageTest.php | 84 +++++++++ .../Component/Asset/Tests/UrlPackageTest.php | 104 +++++++++++ src/Symfony/Component/Asset/UrlPackage.php | 134 ++++++++++++++ .../VersionStrategy/EmptyVersionStrategy.php | 36 ++++ .../VersionStrategy/StaticVersionStrategy.php | 51 ++++++ .../VersionStrategyInterface.php | 38 ++++ src/Symfony/Component/Asset/composer.json | 36 ++++ src/Symfony/Component/Asset/phpunit.xml.dist | 24 +++ .../Component/Templating/Asset/Package.php | 4 + .../Templating/Asset/PackageInterface.php | 4 + .../Templating/Asset/PathPackage.php | 4 + .../Component/Templating/Asset/UrlPackage.php | 4 + .../Templating/Helper/AssetsHelper.php | 4 + .../Templating/Helper/CoreAssetsHelper.php | 4 + ...perTest.php => LegacyAssetsHelperTest.php} | 2 +- ...est.php => LegacyCoreAssetsHelperTest.php} | 2 +- 47 files changed, 1605 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Extension/AssetExtension.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml rename src/Symfony/Bundle/TwigBundle/Tests/Extension/{AssetsExtensionTest.php => LegacyAssetsExtensionTest.php} (98%) create mode 100644 src/Symfony/Component/Asset/.gitignore create mode 100644 src/Symfony/Component/Asset/CHANGELOG.md create mode 100644 src/Symfony/Component/Asset/Context/ContextInterface.php create mode 100644 src/Symfony/Component/Asset/Context/RequestStackContext.php create mode 100644 src/Symfony/Component/Asset/Exception/ExceptionInterface.php create mode 100644 src/Symfony/Component/Asset/Exception/InvalidArgumentException.php create mode 100644 src/Symfony/Component/Asset/Exception/LogicException.php create mode 100644 src/Symfony/Component/Asset/LICENSE create mode 100644 src/Symfony/Component/Asset/Package.php create mode 100644 src/Symfony/Component/Asset/PackageInterface.php create mode 100644 src/Symfony/Component/Asset/Packages.php create mode 100644 src/Symfony/Component/Asset/PathPackage.php create mode 100644 src/Symfony/Component/Asset/README.md create mode 100644 src/Symfony/Component/Asset/Tests/PackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/PackagesTest.php create mode 100644 src/Symfony/Component/Asset/Tests/PathPackageTest.php create mode 100644 src/Symfony/Component/Asset/Tests/UrlPackageTest.php create mode 100644 src/Symfony/Component/Asset/UrlPackage.php create mode 100644 src/Symfony/Component/Asset/VersionStrategy/EmptyVersionStrategy.php create mode 100644 src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php create mode 100644 src/Symfony/Component/Asset/VersionStrategy/VersionStrategyInterface.php create mode 100644 src/Symfony/Component/Asset/composer.json create mode 100644 src/Symfony/Component/Asset/phpunit.xml.dist rename src/Symfony/Component/Templating/Tests/Helper/{AssetsHelperTest.php => LegacyAssetsHelperTest.php} (98%) rename src/Symfony/Component/Templating/Tests/Helper/{CoreAssetsHelperTest.php => LegacyCoreAssetsHelperTest.php} (94%) diff --git a/composer.json b/composer.json index b123e37c78ee9..5a04094969045 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 887e9acf342dd..9da097f7b064a 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_path` function) 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 0000000000000..3f8bb93c3ea32 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\Asset\Packages; + +/** + * Twig extension for the Symfony Asset component. + * + * @author Fabien Potencier + */ +class AssetExtension extends \Twig_Extension +{ + private $packages; + + public function __construct(Packages $packages) + { + $this->packages = $packages; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('asset_path', array($this, 'getAssetPath')), + new \Twig_SimpleFunction('asset_version', array($this, 'getAssetVersion')), + ); + } + + /** + * Returns the public 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 getAssetPath($path, $packageName = 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); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'asset'; + } +} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index c534b8f6acebd..df8a513113bcc 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 39a4e13bbd143..6c0ff55114ff8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -16,6 +16,9 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; +/** + * @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 105326112cd17..c08e177efb1ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -108,6 +108,7 @@ public function getConfigTreeBuilder() $this->addSessionSection($rootNode); $this->addRequestSection($rootNode); $this->addTemplatingSection($rootNode); + $this->addAssetsSection($rootNode); $this->addTranslatorSection($rootNode); $this->addValidationSection($rootNode); $this->addAnnotationsSection($rootNode); @@ -347,8 +348,8 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode) ->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 +371,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode) ->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 +419,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode) ->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 +455,54 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode) ; } + 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 1a38962f16beb..22ac7d34c4f61 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -101,6 +101,10 @@ public function load(array $configs, ContainerBuilder $container) $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); } @@ -632,6 +636,86 @@ private function createTemplatingPackageDefinition(ContainerBuilder $container, return $package; } + /** + * 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) + { + $loader->load('assets.xml'); + + $defaultVersion = $this->createVersion($container, $config['version'], $config['version_format']); + + $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 createPackageDefinition($basePath, array $baseUrls, Reference $version) + { + 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) + ->replaceArgument(0, $basePath) + ->replaceArgument(1, $version) + ; + } + + $package = new DefinitionDecorator('assets.url_package'); + + return $package + ->setPublic(false) + ->replaceArgument(0, $baseUrls) + ->replaceArgument(1, $version) + ; + } + + private function createVersion(ContainerBuilder $container, $version, $format, $name = null) + { + if (!$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); + } + /** * Loads the translator configuration. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml new file mode 100644 index 0000000000000..15dbabd5fe963 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PackageFactory.php index 0a63a29cd6cce..ef76796a26f82 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 @@ * 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 6aa8c58824669..e75e25106ba65 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Asset/PathPackage.php @@ -14,10 +14,14 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\Asset\PathPackage as BasePathPackage; +trigger_error('The Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage is deprecated since version 2.7 and will be removed in 3.0. Use 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/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index dce63a74b99cb..df30fe059e115 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", diff --git a/src/Symfony/Bundle/TwigBundle/CHANGELOG.md b/src/Symfony/Bundle/TwigBundle/CHANGELOG.md index afd8f8177fe3b..82325777bc188 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/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index 59662e8350497..97b6eb68bc11a 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -82,5 +82,9 @@ public function process(ContainerBuilder $container) // we are on Symfony <3.0, where the setContainer method exists $container->getDefinition('twig.app_variable')->addMethodCall('setContainer', array(new Reference('service_container'))); } + + if ($container->has('assets.packages')) { + $container->getDefinition('twig.extension.new_assets')->addTag('twig.extension'); + } } } diff --git a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php index d596f97e528fc..4efc52b0c5359 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php @@ -18,6 +18,8 @@ * 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 { @@ -57,6 +59,8 @@ public function getFunctions() */ public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null) { + trigger_error('The Twig asset() function was deprecated in 2.7 and will be removed in 3.0. Please use asset_path() instead.', E_USER_DEPRECATED); + $url = $this->container->get('templating.helper.assets')->getUrl($path, $packageName, $version); if (!$absolute) { @@ -75,6 +79,8 @@ public function getAssetUrl($path, $packageName = null, $absolute = false, $vers */ 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->container->get('templating.helper.assets')->getVersion($packageName); } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 8f6002d47ebbd..64e74274ff7d9 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -92,6 +92,10 @@ + + + + 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 eddf7adcc0694..425349942f436 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\Tests\TestCase; use Symfony\Component\Routing\RequestContext; -class AssetsExtensionTest extends TestCase +class LegacyAssetsExtensionTest extends TestCase { /** * @dataProvider provideGetGetAssetUrlArguments diff --git a/src/Symfony/Component/Asset/.gitignore b/src/Symfony/Component/Asset/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Asset/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Asset/CHANGELOG.md b/src/Symfony/Component/Asset/CHANGELOG.md new file mode 100644 index 0000000000000..619a423402ada --- /dev/null +++ b/src/Symfony/Component/Asset/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +2.7.0 +----- + + * added the component diff --git a/src/Symfony/Component/Asset/Context/ContextInterface.php b/src/Symfony/Component/Asset/Context/ContextInterface.php new file mode 100644 index 0000000000000..83282021aef17 --- /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/RequestStackContext.php b/src/Symfony/Component/Asset/Context/RequestStackContext.php new file mode 100644 index 0000000000000..ba7113851d863 --- /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 0000000000000..cce1b5ccede8e --- /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 0000000000000..0945d8fad13a4 --- /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 0000000000000..f291d88d52aa4 --- /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 0000000000000..43028bc600f26 --- /dev/null +++ b/src/Symfony/Component/Asset/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php new file mode 100644 index 0000000000000..50f813d86da35 --- /dev/null +++ b/src/Symfony/Component/Asset/Package.php @@ -0,0 +1,75 @@ + + * + * 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; + +/** + * 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) + { + $this->versionStrategy = $versionStrategy; + } + + /** + * {@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); + } + + public function setContext(ContextInterface $context) + { + $this->context = $context; + } + + /** + * @return ContextInterface|null + */ + 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 0000000000000..b9e9ff90b90c8 --- /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 0000000000000..e980b7608e860 --- /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 0000000000000..9f9c4ea17ab00 --- /dev/null +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -0,0 +1,74 @@ + + * + * 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\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) + { + parent::__construct($versionStrategy); + + 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() + { + if (null !== $context = $this->getContext()) { + return $context->getBasePath().$this->basePath; + } + + return $this->basePath; + } +} diff --git a/src/Symfony/Component/Asset/README.md b/src/Symfony/Component/Asset/README.md new file mode 100644 index 0000000000000..f2e66b832e4d6 --- /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 0000000000000..a2310d5898dee --- /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 0000000000000..81db37b996f2c --- /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 0000000000000..3378ee1dcdfbf --- /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)); + $package->setContext($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 0000000000000..7066f84686757 --- /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)); + $package->setContext($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 0000000000000..d675cf0037ea7 --- /dev/null +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -0,0 +1,134 @@ + + * + * 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\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) + { + parent::__construct($versionStrategy); + + 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 && ($context = $this->getContext()) && $context->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 0000000000000..aa06eaa55ee7c --- /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 0000000000000..6028eb57fe5dd --- /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 0000000000000..a0fb260033656 --- /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 0000000000000..cf058bb3b20b1 --- /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 0000000000000..547ecdaa7a44e --- /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 02a1269bd95ad..cfc33ccbcf92e 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 7317b555ac476..f19f6fc3c42f5 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 1806107f6dfca..48f69523df095 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 00a21670f4459..2ab1d0f9d53a6 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 128843ef0d39d..aceff61b61be9 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 @@ * * @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 b2d06a336268b..41076a1bfb5b8 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 @@ * * @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 98% rename from src/Symfony/Component/Templating/Tests/Helper/AssetsHelperTest.php rename to src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php index c29c6de1a332c..8ce72c3fc1960 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/AssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php @@ -13,7 +13,7 @@ use Symfony\Component\Templating\Helper\AssetsHelper; -class AssetsHelperTest extends \PHPUnit_Framework_TestCase +class LegacyAssetsHelperTest extends \PHPUnit_Framework_TestCase { public function testGetVersion() { diff --git a/src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php similarity index 94% rename from src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php rename to src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php index b681e9fab6926..6fe6423b67267 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/CoreAssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php @@ -13,7 +13,7 @@ use Symfony\Component\Templating\Helper\CoreAssetsHelper; -class CoreAssetsHelperTest extends \PHPUnit_Framework_TestCase +class LegacyCoreAssetsHelperTest extends \PHPUnit_Framework_TestCase { protected $package; From 4d0adeae16bf6733e637089b8121e25752e0d604 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 19 Jan 2015 20:26:55 +0100 Subject: [PATCH 2/4] [Asset] added a NullContext class --- .../Resources/config/assets.xml | 8 +--- .../Component/Asset/Context/NullContext.php | 38 +++++++++++++++++++ src/Symfony/Component/Asset/Package.php | 11 ++---- src/Symfony/Component/Asset/PathPackage.php | 11 ++---- .../Component/Asset/Tests/PathPackageTest.php | 4 +- .../Component/Asset/Tests/UrlPackageTest.php | 4 +- src/Symfony/Component/Asset/UrlPackage.php | 7 ++-- 7 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 src/Symfony/Component/Asset/Context/NullContext.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 15dbabd5fe963..4e7a1b8f6b8d2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -18,17 +18,13 @@ - - - + - - - + diff --git a/src/Symfony/Component/Asset/Context/NullContext.php b/src/Symfony/Component/Asset/Context/NullContext.php new file mode 100644 index 0000000000000..47d29d7d2e33c --- /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/Package.php b/src/Symfony/Component/Asset/Package.php index 50f813d86da35..43bdcf21db68a 100644 --- a/src/Symfony/Component/Asset/Package.php +++ b/src/Symfony/Component/Asset/Package.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Asset; use Symfony\Component\Asset\Context\ContextInterface; +use Symfony\Component\Asset\Context\NullContext; use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; /** @@ -25,9 +26,10 @@ class Package implements PackageInterface private $versionStrategy; private $context; - public function __construct(VersionStrategyInterface $versionStrategy) + public function __construct(VersionStrategyInterface $versionStrategy, ContextInterface $context = null) { $this->versionStrategy = $versionStrategy; + $this->context = $context ?: new NullContext(); } /** @@ -50,13 +52,8 @@ public function getUrl($path) return $this->versionStrategy->applyVersion($path); } - public function setContext(ContextInterface $context) - { - $this->context = $context; - } - /** - * @return ContextInterface|null + * @return ContextInterface */ protected function getContext() { diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php index 9f9c4ea17ab00..906879f8b064d 100644 --- a/src/Symfony/Component/Asset/PathPackage.php +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Asset; +use Symfony\Component\Asset\Context\ContextInterface; use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; /** @@ -31,9 +32,9 @@ class PathPackage extends Package * @param string $basePath The base path to be prepended to relative paths * @param VersionStrategyInterface $versionStrategy The version strategy */ - public function __construct($basePath, VersionStrategyInterface $versionStrategy) + public function __construct($basePath, VersionStrategyInterface $versionStrategy, ContextInterface $context = null) { - parent::__construct($versionStrategy); + parent::__construct($versionStrategy, $context); if (!$basePath) { $this->basePath = '/'; @@ -65,10 +66,6 @@ public function getUrl($path) */ public function getBasePath() { - if (null !== $context = $this->getContext()) { - return $context->getBasePath().$this->basePath; - } - - return $this->basePath; + return $this->getContext()->getBasePath().$this->basePath; } } diff --git a/src/Symfony/Component/Asset/Tests/PathPackageTest.php b/src/Symfony/Component/Asset/Tests/PathPackageTest.php index 3378ee1dcdfbf..ff5b0a052f14a 100644 --- a/src/Symfony/Component/Asset/Tests/PathPackageTest.php +++ b/src/Symfony/Component/Asset/Tests/PathPackageTest.php @@ -52,8 +52,8 @@ public function getConfigs() */ public function testGetUrlWithContext($basePathRequest, $basePath, $format, $path, $expected) { - $package = new PathPackage($basePath, new StaticVersionStrategy('v1', $format)); - $package->setContext($this->getContext($basePathRequest)); + $package = new PathPackage($basePath, new StaticVersionStrategy('v1', $format), $this->getContext($basePathRequest)); + $this->assertEquals($expected, $package->getUrl($path)); } diff --git a/src/Symfony/Component/Asset/Tests/UrlPackageTest.php b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php index 7066f84686757..515bd926eac0b 100644 --- a/src/Symfony/Component/Asset/Tests/UrlPackageTest.php +++ b/src/Symfony/Component/Asset/Tests/UrlPackageTest.php @@ -57,8 +57,8 @@ public function getConfigs() */ public function testGetUrlWithContext($secure, $baseUrls, $format, $path, $expected) { - $package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format)); - $package->setContext($this->getContext($secure)); + $package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format), $this->getContext($secure)); + $this->assertEquals($expected, $package->getUrl($path)); } diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php index d675cf0037ea7..0e9f82d0fa65a 100644 --- a/src/Symfony/Component/Asset/UrlPackage.php +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -11,6 +11,7 @@ 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; @@ -42,9 +43,9 @@ class UrlPackage extends Package * @param string|array $baseUrls Base asset URLs * @param VersionStrategyInterface $versionStrategy The version strategy */ - public function __construct($baseUrls = array(), VersionStrategyInterface $versionStrategy) + public function __construct($baseUrls = array(), VersionStrategyInterface $versionStrategy, ContextInterface $context = null) { - parent::__construct($versionStrategy); + parent::__construct($versionStrategy, $context); if (!is_array($baseUrls)) { $baseUrls = (array) $baseUrls; @@ -74,7 +75,7 @@ public function getUrl($path) return $path; } - if (null !== $this->sslPackage && ($context = $this->getContext()) && $context->isSecure()) { + if (null !== $this->sslPackage && $this->getContext()->isSecure()) { return $this->sslPackage->getUrl($path); } From f74a1f2dc34d8b141e1f4bfbbfa1dbb7d955fe42 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 17 Jan 2015 08:35:04 +0100 Subject: [PATCH 3/4] renamed asset_path() to asset() and added a BC layer --- src/Symfony/Bridge/Twig/CHANGELOG.md | 2 +- .../Bridge/Twig/Extension/AssetExtension.php | 73 +++++++++- .../Tests/Extension/AssetExtensionTest.php | 40 ++++++ .../Compiler/TemplatingAssetHelperPass.php | 2 + .../DependencyInjection/Configuration.php | 38 ++++++ .../FrameworkExtension.php | 94 +------------ .../FrameworkBundle/FrameworkBundle.php | 2 - .../Resources/config/assets.xml | 6 +- .../Resources/config/schema/symfony-1.0.xsd | 27 +++- .../Resources/config/templating.xml | 11 -- .../Resources/config/templating_php.xml | 7 + .../Templating/Helper/AssetsHelper.php | 126 ++++++++++++++++++ ...> LegacyTemplatingAssetHelperPassTest.php} | 2 +- .../Fixtures/php/assets.php | 25 ++++ .../DependencyInjection/Fixtures/php/full.php | 14 -- .../Fixtures/php/legacy_templating_assets.php | 23 ++++ ....php => legacy_templating_url_package.php} | 0 .../Fixtures/xml/assets.xml | 23 ++++ .../DependencyInjection/Fixtures/xml/full.xml | 12 +- .../Fixtures/xml/legacy_templating_assets.xml | 23 ++++ ....xml => legacy_templating_url_package.xml} | 0 .../Fixtures/yml/assets.yml | 16 +++ .../DependencyInjection/Fixtures/yml/full.yml | 10 -- .../Fixtures/yml/legacy_templating_assets.yml | 15 +++ ....yml => legacy_templating_url_package.yml} | 0 .../FrameworkExtensionTest.php | 95 ++++++++++--- .../PhpFrameworkExtensionTest.php | 34 +++++ .../Tests/Templating/Helper/AssetsHelper.php | 46 +++++++ .../Bundle/FrameworkBundle/composer.json | 1 + .../Compiler/ExtensionPass.php | 4 - .../TwigBundle/Extension/AssetsExtension.php | 6 +- .../TwigBundle/Resources/config/twig.xml | 9 +- .../Tests/Helper/LegacyAssetsHelperTest.php | 5 + .../Helper/LegacyCoreAssetsHelperTest.php | 2 + 34 files changed, 613 insertions(+), 180 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Tests/Extension/AssetExtensionTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Templating/Helper/AssetsHelper.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/{TemplatingAssetHelperPassTest.php => LegacyTemplatingAssetHelperPassTest.php} (98%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/legacy_templating_assets.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{templating_url_package.php => legacy_templating_url_package.php} (100%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/assets.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/legacy_templating_assets.xml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{templating_url_package.xml => legacy_templating_url_package.xml} (100%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/legacy_templating_assets.yml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/{templating_url_package.yml => legacy_templating_url_package.yml} (100%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/AssetsHelper.php diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 9da097f7b064a..9781390321412 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -6,7 +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_path` function) + * 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 index 3f8bb93c3ea32..3e9e9f6a78e27 100644 --- a/src/Symfony/Bridge/Twig/Extension/AssetExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/AssetExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\Extension; use Symfony\Component\Asset\Packages; +use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; /** * Twig extension for the Symfony Asset component. @@ -21,10 +22,16 @@ class AssetExtension extends \Twig_Extension { private $packages; + private $foundationExtension; - public function __construct(Packages $packages) + /** + * 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; } /** @@ -33,13 +40,14 @@ public function __construct(Packages $packages) public function getFunctions() { return array( - new \Twig_SimpleFunction('asset_path', array($this, 'getAssetPath')), + 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 path of an asset. + * 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. @@ -49,8 +57,20 @@ public function getFunctions() * * @return string The public path of the asset */ - public function getAssetPath($path, $packageName = null) + 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); } @@ -67,6 +87,51 @@ 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. * 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 0000000000000..4c67f4fd1901d --- /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/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php index 6c0ff55114ff8..5e59391e9c884 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TemplatingAssetHelperPass.php @@ -16,6 +16,8 @@ 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 */ diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index c08e177efb1ca..95aa34c50ef74 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -53,6 +53,44 @@ public function getConfigTreeBuilder() 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') diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 22ac7d34c4f61..bbd824e1d1472 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -49,6 +49,7 @@ public function load(array $configs, ContainerBuilder $container) $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 @@ -473,23 +474,6 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB $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); @@ -569,73 +553,6 @@ private function registerTemplatingConfiguration(array $config, $ide, ContainerB } } - /** - * Returns a definition for an asset package. - */ - private function createTemplatingPackageDefinition(ContainerBuilder $container, array $httpUrls, array $sslUrls, $version, $format, $name = null) - { - if (!$httpUrls) { - $package = new DefinitionDecorator('templating.asset.path_package'); - $package - ->setPublic(false) - ->setScope('request') - ->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 - ->setPublic(false) - ->setScope('request') - ->replaceArgument(1, $prefix.'.http') - ->replaceArgument(2, $prefix.'.ssl') - ; - - return $package; - } - /** * Loads the assets configuration. * @@ -645,9 +562,7 @@ private function createTemplatingPackageDefinition(ContainerBuilder $container, */ private function registerAssetsConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) { - $loader->load('assets.xml'); - - $defaultVersion = $this->createVersion($container, $config['version'], $config['version_format']); + $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); @@ -658,7 +573,6 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co $version = $defaultVersion; } else { $format = $package['version_format'] ?: $config['version_format']; - $version = $this->createVersion($container, $package['version'], $format, $name); } @@ -700,9 +614,9 @@ private function createPackageDefinition($basePath, array $baseUrls, Reference $ ; } - private function createVersion(ContainerBuilder $container, $version, $format, $name = null) + private function createVersion(ContainerBuilder $container, $version, $format, $name) { - if (!$version) { + if (null === $version) { return new Reference('assets.empty_version_strategy'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 5ddc397560027..499f39c6c95c0 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\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 @@ public function build(ContainerBuilder $container) // but as late as possible to get resolved parameters $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); - $container->addCompilerPass(new TemplatingAssetHelperPass()); $container->addCompilerPass(new AddConstraintValidatorsPass()); $container->addCompilerPass(new AddValidatorInitializersPass()); $container->addCompilerPass(new AddConsoleCommandPass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml index 4e7a1b8f6b8d2..4f2e1fbf362a0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/assets.xml @@ -7,10 +7,14 @@ - + + + + + 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 cc3cd1de47a60..652d168a77266 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 efec555b87cad..59da78fc41689 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 5b4f8073feeb2..556206d43ba09 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/Helper/AssetsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/AssetsHelper.php new file mode 100644 index 0000000000000..dcbb6bfe5669b --- /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 3a096715e160b..10a6e08568b04 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\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 0000000000000..e3532a7747cc6 --- /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 ab356dafd7c22..679da4161d4fd 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 @@ '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 0000000000000..32bd56b3587d5 --- /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 0000000000000..e39e15f900528 --- /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 024cef66cc0ae..4f41288410e0c 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 0000000000000..963848f767763 --- /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 0000000000000..193dc59dfba3a --- /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 d16f24c4cafb6..3fd70b7eba38e 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 0000000000000..e8cc6ce41d31c --- /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 8e112baf2a634..344065d623c8e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -14,6 +14,8 @@ 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 @@ public function testTemplating() $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 @@ public function testTemplating() $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 @@ protected function createContainerFromFile($file, $data = array()) 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 fad373e47160c..01c73930db8b1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -22,4 +22,38 @@ protected function loadFromFile(ContainerBuilder $container, $file) $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 0000000000000..7ef641d756974 --- /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 df30fe059e115..6d57657ef10d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -48,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/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index 97b6eb68bc11a..59662e8350497 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -82,9 +82,5 @@ public function process(ContainerBuilder $container) // we are on Symfony <3.0, where the setContainer method exists $container->getDefinition('twig.app_variable')->addMethodCall('setContainer', array(new Reference('service_container'))); } - - if ($container->has('assets.packages')) { - $container->getDefinition('twig.extension.new_assets')->addTag('twig.extension'); - } } } diff --git a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php index 4efc52b0c5359..9d03aa7079010 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php @@ -14,6 +14,8 @@ 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. * @@ -59,8 +61,6 @@ public function getFunctions() */ public function getAssetUrl($path, $packageName = null, $absolute = false, $version = null) { - trigger_error('The Twig asset() function was deprecated in 2.7 and will be removed in 3.0. Please use asset_path() instead.', E_USER_DEPRECATED); - $url = $this->container->get('templating.helper.assets')->getUrl($path, $packageName, $version); if (!$absolute) { @@ -79,8 +79,6 @@ public function getAssetUrl($path, $packageName = null, $absolute = false, $vers */ 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->container->get('templating.helper.assets')->getVersion($packageName); } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 64e74274ff7d9..83bb14735d8d5 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,14 +85,10 @@ - + - - - - - + diff --git a/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php b/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php index 8ce72c3fc1960..a3e61fb9756f2 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyAssetsHelperTest.php @@ -15,6 +15,11 @@ 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/LegacyCoreAssetsHelperTest.php b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php index 6fe6423b67267..65695ee6eb38f 100644 --- a/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php +++ b/src/Symfony/Component/Templating/Tests/Helper/LegacyCoreAssetsHelperTest.php @@ -19,6 +19,8 @@ class LegacyCoreAssetsHelperTest extends \PHPUnit_Framework_TestCase protected function setUp() { + $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); + $this->package = $this->getMock('Symfony\Component\Templating\Asset\PackageInterface'); } From 0750d02025e078e983571fb1c0fb77ae7f9aaa52 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 10 Feb 2015 13:56:33 +0100 Subject: [PATCH 4/4] removed usage of the deprecated forms of asset() in the core framework --- .../Resources/views/Exception/exception_full.html.twig | 2 +- .../Bundle/TwigBundle/Resources/views/layout.html.twig | 4 ++-- .../Tests/DependencyInjection/WebProfilerExtensionTest.php | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) 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 f97c60b9e499d..24d437d45e816 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 75cf10904859b..ef59ed5408a05 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/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php index f1992bbe9f71d..132315fd23c82 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/DependencyInjection/WebProfilerExtensionTest.php @@ -52,9 +52,6 @@ protected function setUp() $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__); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy