8000 Cookbook entry: Asset - Custom Version Strategy · symfony/symfony-docs@cb1c157 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb1c157

Browse files
committed
Cookbook entry: Asset - Custom Version Strategy
1 parent 4500f1c commit cb1c157

File tree

5 files changed

+277
-0
lines changed

5 files changed

+277
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
.. index::
2+
single: Asset; Custom Version Strategy
3+
4+
How to use a Custom Version Strategy for Assets
5+
===============================================
6+
7+
Symfony by default does not perform asset versioning. You can specify the
8+
:ref:`version <reference-framework-assets-version>` and
9+
:ref:`version_format <reference-framework-assets-version-format>` configuration
10+
options to add a simple version to all assets (or a specific set of assets
11+
grouped as a :ref:`package <reference-framework-assets-packages>`).
12+
13+
.. versionadded:: 2.7
14+
The Asset component was introduced in Symfony 2.7.
15+
16+
.. configuration-block::
17+
18+
.. code-block:: yaml
19+
20+
# app/config/config.yml
21+
framework:
22+
assets:
23+
version: "20150530"
24+
version_format: "%%s?version=%%s"
25+
26+
.. code-block:: xml
27+
28+
<!-- app/config/config.xml -->
29+
<?xml version="1.0" encoding="UTF-8" ?>
30+
<container xmlns="http://symfony.com/schema/dic/services"
31+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
32+
xmlns:framework="http://symfony.com/schema/dic/symfony"
33+
xsi:schemaLocation="http://symfony.com/schema/dic/services
34+
http://symfony.com/schema/dic/services/services-1.0.xsd
35+
http://symfony.com/schema/dic/symfony
36+
http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
37+
38+
<framework:config>
39+
<framework:assets
40+
version="20150530"
41+
version-format="%%s?version=%%s" />
42+
</framework:config>
43+
</container>
44+
45+
.. code-block:: php
46+
47+
// app/config/config.php
48+
$container->loadFromExtension('framework', array(
49+
'assets' => array(
50+
'version' => '20150530',
51+
'version_format' => '%%s?version=%%s',
52+
),
53+
));
54+
55+
However, if you require more control, you need to create a custom version
56+
strategy.
57+
58+
Default Package
59+
---------------
60+
61+
The default package is used when you do not specify a package name in the
62+
:ref:`asset <reference-twig-function-asset>` Twig function. In order to
63+
override the version strategy used by the default package, it is necessary
64+
to add a compiler pass.
65+
66+
This example shows how to integrate with `gulp-buster`_.
67+
68+
.. note::
69+
70+
busters.json as referenced below is the output from gulp-buster which
71+
maps each asset file to its hash. A small snippet of the file's format
72+
(JSON object):
73+
74+
.. code-block:: json
75+
76+
{
77+
"js/script.js": "f9c7afd05729f10f55b689f36bb20172",
78+
"css/style.css": "91cd067f79a5839536b46c494c4272d8"
79+
}
80+
81+
Create Compiler Pass
82+
~~~~~~~~~~~~~~~~~~~~
83+
84+
.. code-block:: php
85+
86+
// src/AppBundle/DependencyInjection/Compiler/OverrideAssetsDefaultPackagePass.php
87+
namespace AppBundle\DependencyInjection\Compiler;
88+
89+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
90+
use Symfony\Component\DependencyInjection\ContainerBuilder;
91+
use Symfony\Component\DependencyInjection\Reference;
92+
93+
class OverrideAssetsDefaultPackagePass implements CompilerPassInterface
94+
{
95+
public function process(ContainerBuilder $container)
96+
{
97+
$definition = $container->getDefinition('assets._default_package');
98+
$definition->replaceArgument(1, new Reference('app.assets.buster_version_strategy'));
99+
}
100+
}
101+
102+
The code above fetches the service definition of the default package, and replaces
103+
its second argument (the version strategy).
104+
105+
Register Compiler Pass
106+
~~~~~~~~~~~~~~~~~~~~~~
107+
108+
.. code-block:: php
109+
110+
// src/AppBundle/AppBundle.php
111+
namespace AppBundle;
112+
113+
use AppBundle\DependencyInjection\Compiler\OverrideAssetsDefaultPackagePass;
114+
use Symfony\Component\DependencyInjection\ContainerBuilder;
115+
use Symfony\Component\HttpKernel\Bundle\Bundle;
116+
117+
class AppBundle extends Bundle
118+
{
119+
public function build(ContainerBuilder $container)
120+
{
121+
parent::build($container);
122+
123+
// only register in prod environment
124+
if ('prod' === $container->getParameter('kernel.environment')) {
125+
$container->addCompilerPass(new OverrideAssetsDefaultPackagePass());
126+
}
127+
}
128+
}
129+
130+
See :doc:`/cookbook/service_container/compiler_passes` for more information
131+
on how to use compiler passes.
132+
133+
Register Services
134+
~~~~~~~~~~~~~~~~~
135+
136+
.. configuration-block::
137+
138+
.. code-block:: yaml
139+
140+
# app/config/services.yml
141+
services:
142+
app.assets.buster_version_strategy:
143+
class: AppBundle\Asset\VersionStrategy\BusterVersionStrategy
144+
arguments:
145+
- manifest_path: "%kernel.root_dir%/../busters.json"
146+
format: "%%s?version=%%s"
147+
public: false
148+
149+
.. code-block:: xml
150+
151+
<!-- app/config/services.xml -->
152+
<?xml version="1.0" encoding="UTF-8" ?>
153+
<container xmlns="http://symfony.com/schema/dic/services"
154+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
155+
xsi:schemaLocation="http://symfony.com/schema/dic/services
156+
http://symfony.com/schema/dic/services/services-1.0.xsd">
157+
158+
<services>
159+
160+
<service id="app.assets.buster_version_strategy" class="AppBundle\Asset\VersionStrategy\BusterVersionStrategy" public="false">
161+
<argument type="collection">
162+
<argument key="manifest_path">%kernel.root_dir%/../busters.json</argument>
163+
<argument key="format">%%s?version=%%s</argument>
164+
</argument>
165+
</service>
166+
167+
</services>
168+
</container>
169+
170+
.. code-block:: php
171+
172+
// app/config/services.php
173+
use Symfony\Component\DependencyInjection\Definition;
174+
175+
$definition = new Definition(
176+
'AppBundle\Asset\VersionStrategy\BusterVersionStrategy',
177+
array(
178+
array(
179+
'manifest_path' => '%kernel.root_dir%/../busters.json',
180+
'format' => '%%s?version=%%s',
181+
),
182+
)
183+
);
184+
$definition->setPublic(false);
185+
186+
$container->setDefinition('app.assets.buster_version_strategy', $definition);
187+
188+
Implement VersionStrategyInterface
189+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190+
191+
.. code-block:: php
192+
193+
// src/AppBundle/Asset/VersionStrategy/BusterVersionStrategy.php
194+
namespace AppBundle\Asset\VersionStrategy;
195+
196+
use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;
197+
198+
class BusterVersionStrategy implements VersionStrategyInterface
199+
{
200+
/**
201+
* @var string
202+
*/
203+
private $manifestPath;
204+
205+
/**
206+
* @var string
207+
*/
208+
private $format;
209+
210+
/**
211+
* @var string[]
212+
*/
213+
private $hashes;
214+
215+
/**
216+
* @param array $options {
217+
* @var string $manifest_path
218+
* @var string|null $format
219+
* }
220+
*/
221+
public function __construct(array $options)
222+
{
223+
$this->manifestPath = $options['manifest_path'];
224+
$this->format = isset($options['format']) ? $options['format'] : '%s?%s';
225+
}
226+
227+
public function getVersion($path)
228+
{
229+
if (!is_array($this->hashes)) {
230+
$this->hashes = $this->loadManifest();
231+
}
232+
233+
return isset($this->hashes[$path]) ? $this->hashes[$path] : '';
234+
}
235+
236+
public function applyVersion($path)
237+
{
238+
$version = $this->getVersion($path);
239+
240+
if ('' === $version) {
241+
return $path;
242+
}
243+
244+
$versionized = sprintf($this->format, ltrim($path, '/'), $version);
245+
246+
if ($path && '/' === $path[0]) {
247+
return '/'.$versionized;
248+
}
249+
250+
return $versionized;
251+
}
252+
253+
private function loadManifest(array $options)
254+
{
255+
$hashes = json_decode(
256+
file_get_contents(realpath($this->manifestPath)),
257+
$assoc = true
258+
);
259+
260+
return $hashes;
261+
}
262+
}
263+
264+
.. _`gulp-buster`: https://www.npmjs.com/package/gulp-buster

cookbook/asset/index.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Asset
2+
=====
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
7+
custom_version_strategy

cookbook/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ The Cookbook
44
.. toctree::
55
:hidden:
66

7+
asset/index
78
assetic/index
89
bundles/index
910
cache/index

reference/configuration/framework.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,7 @@ option.
936936
``assets_version``. This makes it easier to increment the cache on each
937937
deployment.
938938

939+
.. _reference-framework-assets-version-format:
939940
.. _reference-templating-version-format:
940941

941942
assets_version_format
@@ -1209,6 +1210,8 @@ templating loaders. Templating loaders are used to find and load templates
12091210
from a resource (e.g. a filesystem or database). Templating loaders must
12101211
implement :class:`Symfony\\Component\\Templating\\Loader\\LoaderInterface`.
12111212

1213+
.. _reference-framework-assets-packages:
1214+
12121215
packages
12131216
........
12141217

reference/twig_reference.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ Returns an instance of ``ControllerReference`` to be used with functions
9393
like :ref:`render() <reference-twig-function-render>` and
9494
:ref:`render_esi() <reference-twig-function-render-esi>`.
9595

96+
.. _reference-twig-function-asset:
97+
9698
asset
9799
~~~~~
98100

0 commit comments

Comments
 (0)
0