From b770f79211d20d9ee4a90009d1a8af95d6f7013e Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Mon, 6 Jul 2015 05:16:26 +0800 Subject: [PATCH] Cookbook entry: Asset - Custom Version Strategy --- cookbook/asset/custom_version_strategy.rst | 254 +++++++++++++++++++++ cookbook/asset/index.rst | 7 + cookbook/index.rst | 1 + cookbook/map.rst.inc | 4 + reference/configuration/framework.rst | 3 + reference/twig_reference.rst | 2 + 6 files changed, 271 insertions(+) create mode 100644 cookbook/asset/custom_version_strategy.rst create mode 100644 cookbook/asset/index.rst diff --git a/cookbook/asset/custom_version_strategy.rst b/cookbook/asset/custom_version_strategy.rst new file mode 100644 index 00000000000..4d42a2981d2 --- /dev/null +++ b/cookbook/asset/custom_version_strategy.rst @@ -0,0 +1,254 @@ +.. index:: + single: Asset; Custom Version Strategy + +How to Use a Custom Version Strategy for Assets +=============================================== + +.. versionadded:: 2.7 + The Asset component was introduced in Symfony 2.7. + +Symfony by default does not perform asset versioning. You can specify the +:ref:`version ` and +:ref:`version_format ` configuration +options to add a simple version to all assets (or a specific set of assets +grouped as a :ref:`package `): + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + assets: + version: "20150530" + version_format: "%%s?version=%%s" + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + 'assets' => array( + 'version' => '20150530', + 'version_format' => '%%s?version=%%s', + ), + )); + +However, if you require more control, you need to create a custom version +strategy. + +Default Package +--------------- + +The default package is used when you do not specify a package name in the +:ref:`asset ` Twig function. In order to +override the version strategy used by the default package, it is necessary +to add a compiler pass. + +This example shows how to integrate with `gulp-buster`_. + +.. note:: + + busters.json as referenced below is the output from gulp-buster which + maps each asset file to its hash. A small snippet of the file's format + (JSON object): + + .. code-block:: json + + { + "js/script.js": "f9c7afd05729f10f55b689f36bb20172", + "css/style.css": "91cd067f79a5839536b46c494c4272d8" + } + +Create Compiler Pass +~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + // src/AppBundle/DependencyInjection/Compiler/OverrideAssetsDefaultPackagePass.php + namespace AppBundle\DependencyInjection\Compiler; + + use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\DependencyInjection\Reference; + + class OverrideAssetsDefaultPackagePass implements CompilerPassInterface + { + public function process(ContainerBuilder $container) + { + $definition = $container->getDefinition('assets._default_package'); + $definition->replaceArgument(1, new Reference('app.assets.buster_version_strategy')); + } + } + +The code above fetches the service definition of the default package, and replaces +its second argument (the version strategy). + +Register Compiler Pass +~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + // src/AppBundle/AppBundle.php + namespace AppBundle; + + use AppBundle\DependencyInjection\Compiler\OverrideAssetsDefaultPackagePass; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\HttpKernel\Bundle\Bundle; + + class AppBundle extends Bundle + { + public function build(ContainerBuilder $container) + { + parent::build($container); + + // only register in prod environment + if ('prod' === $container->getParameter('kernel.environment')) { + $container->addCompilerPass(new OverrideAssetsDefaultPackagePass()); + } + } + } + +See :doc:`/cookbook/service_container/compiler_passes` for more information +on how to use compiler passes. + +Register Services +~~~~~~~~~~~~~~~~~ + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + services: + app.assets.buster_version_strategy: + class: AppBundle\Asset\VersionStrategy\BusterVersionStrategy + arguments: + - "%kernel.root_dir%/../busters.json" + - "%%s?version=%%s" + public: false + + .. code-block:: xml + + + + + + + %kernel.root_dir%/../busters.json + %%s?version=%%s + + + + + .. code-block:: php + + // app/config/services.php + use Symfony\Component\DependencyInjection\Definition; + + $definition = new Definition( + 'AppBundle\Asset\VersionStrategy\BusterVersionStrategy', + array( + '%kernel.root_dir%/../busters.json', + '%%s?version=%%s', + ) + ); + $definition->setPublic(false); + + $container->setDefinition('app.assets.buster_version_strategy', $definition); + +Implement VersionStrategyInterface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: php + + // src/AppBundle/Asset/VersionStrategy/BusterVersionStrategy.php + namespace AppBundle\Asset\VersionStrategy; + + use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; + + class BusterVersionStrategy implements VersionStrategyInterface + { + /** + * @var string + */ + private $manifestPath; + + /** + * @var string + */ + private $format; + + /** + * @var string[] + */ + private $hashes; + + /** + * @param string $manifestPath + * @param string|null $format + */ + public function __construct($manifestPath, $format = null) + { + $this->manifestPath = $manifestPath; + $this->format = $format ?: '%s?%s'; + } + + public function getVersion($path) + { + if (!is_array($this->hashes)) { + $this->hashes = $this->loadManifest(); + } + + return isset($this->hashes[$path]) ? $this->hashes[$path] : ''; + } + + public function applyVersion($path) + { + $version = $this->getVersion($path); + + if ('' === $version) { + return $path; + } + + $versionized = sprintf($this->format, ltrim($path, '/'), $version); + + if ($path && '/' === $path[0]) { + return '/'.$versionized; + } + + return $versionized; + } + + private function loadManifest(array $options) + { + $hashes = json_decode(file_get_contents($this->manifestPath), true); + + return $hashes; + } + } + +.. _`gulp-buster`: https://www.npmjs.com/package/gulp-buster diff --git a/cookbook/asset/index.rst b/cookbook/asset/index.rst new file mode 100644 index 00000000000..72838e118cd --- /dev/null +++ b/cookbook/asset/index.rst @@ -0,0 +1,7 @@ +Asset +===== + +.. toctree:: + :maxdepth: 2 + + custom_version_strategy diff --git a/cookbook/index.rst b/cookbook/index.rst index bdf414d6177..f60f52f30b2 100644 --- a/cookbook/index.rst +++ b/cookbook/index.rst @@ -4,6 +4,7 @@ The Cookbook .. toctree:: :hidden: + asset/index assetic/index bundles/index cache/index diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc index b7563d7f6b8..3a6e6ce929f 100644 --- a/cookbook/map.rst.inc +++ b/cookbook/map.rst.inc @@ -1,3 +1,7 @@ +* :doc:`/cookbook/asset/index` + + * :doc:`/cookbook/asset/custom_version_strategy` + * :doc:`/cookbook/assetic/index` * :doc:`/cookbook/assetic/asset_management` diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b54f708185c..23f60b22c66 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -936,6 +936,7 @@ option. ``assets_version``. This makes it easier to increment the cache on each deployment. +.. _reference-framework-assets-version-format: .. _reference-templating-version-format: assets_version_format @@ -1209,6 +1210,8 @@ templating loaders. Templating loaders are used to find and load templates from a resource (e.g. a filesystem or database). Templating loaders must implement :class:`Symfony\\Component\\Templating\\Loader\\LoaderInterface`. +.. _reference-framework-assets-packages: + packages ........ diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 55e55195f2c..605d4e388bd 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -93,6 +93,8 @@ Returns an instance of ``ControllerReference`` to be used with functions like :ref:`render() ` and :ref:`render_esi() `. +.. _reference-twig-function-asset: + asset ~~~~~