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

Skip to content

Commit b770f79

Browse files
committed
Cookbook entry: Asset - Custom Version Strategy
1 parent 40d8d00 commit b770f79

File tree

6 files changed

+271
-0
lines changed

6 files changed

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

cookbook/map.rst.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* :doc:`/cookbook/asset/index`
2+
3+
* :doc:`/cookbook/asset/custom_version_strategy`
4+
15
* :doc:`/cookbook/assetic/index`
26

37
* :doc:`/cookbook/assetic/asset_management`

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