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

Skip to content

Commit 8d71390

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

File tree

5 files changed

+272
-0
lines changed

5 files changed

+272
-0
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
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 strategy.
56+
57+
Default Package
58+
---------------
59+
60+
The default package is used when you do not specify a package name in the
61+
:ref:`asset <reference-twig-function-asset>` Twig function. In order to
62+
override the version strategy used by the default package, it is necessary
63+
to add a compiler pass.
64+
65+
This example shows how to integrate with `gulp-buster`_. Note: busters.json
66+
as referenced below is the output from gulp-buster which maps each asset
67+
file to its hash. A small snippet of the file's format (JSON object):
68+
69+
.. code-block:: json
70+
71+
{
72+
"js/script.js": "f9c7afd05729f10f55b689f36bb20172",
73+
"css/style.css": "91cd067f79a5839536b46c494c4272d8"
74+
}
75+
76+
Create Compiler Pass
77+
~~~~~~~~~~~~~~~~~~~~
78+
79+
.. code-block:: php
80+
81+
// src/AppBundle/DependencyInjection/Compiler/OverrideAssetsDefaultPackagePass.php
82+
namespace AppBundle\DependencyInjection\Compiler;
83+
84+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
85+
use Symfony\Component\DependencyInjection\ContainerBuilder;
86+
use Symfony\Component\DependencyInjection\Reference;
87+
88+
class OverrideAssetsDefaultPackagePass implements CompilerPassInterface
89+
{
90+
public function process(ContainerBuilder $container)
91+
{
92+
$definition = $container->getDefinition('assets._default_package');
93+
$definition->replaceArgument(1, new Reference('app.assets.buster_version_strategy'));
94+
}
95+
}
96+
97+
The code above fetches the service definition of the default package, and replaces
98+
its second argument (the version strategy).
99+
100+
Register Compiler Pass
101+
~~~~~~~~~~~~~~~~~~~~~~
102+
103+
.. code-block:: php
104+
105+
// src/AppBundle/AppBundle.php
106+
namespace AppBundle;
107+
108+
use AppBundle\DependencyInjection\Compiler\OverrideAssetsDefaultPackagePass;
109+
use Symfony\Component\DependencyInjection\ContainerBuilder;
110+
use Symfony\Component\HttpKernel\Bundle\Bundle;
111+
112+
class AppBundle extends Bundle
113+
{
114+
public function build(ContainerBuilder $container)
115+
{
116+
parent::build($container);
117+
118+
// only register in prod environment
119+
if ('prod' === $container->getParameter('kernel.environment')) {
120+
$container->addCompilerPass(new OverrideAssetsDefaultPackagePass());
121+
}
122+
}
123+
}
124+
125+
See :doc:`/cookbook/service_container/compiler_passes` for more information
126+
on how to use compiler passes.
127+
128+
Register Services
< 10000 code>129+
~~~~~~~~~~~~~~~~~
130+
131+
.. configuration-block::
132+
133+
.. code-block:: yaml
134+
135+
# app/config/services.yml
136+
services:
137+
app.assets.buster_version_strategy:
138+
class: AppBundle\Asset\VersionStrategy\BusterVersionStrategy
139+
arguments:
140+
- manifest_path: "%kernel.root_dir%/../busters.json"
141+
format: "%%s?version=%%s"
142+
public: false
143+
144+
.. code-block:: xml
145+
146+
<!-- app/config/services.xml -->
147+
<?xml version="1.0" encoding="UTF-8" ?>
148+
<container xmlns="http://symfony.com/schema/dic/services"
149+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
150+
xsi:schemaLocation="http://symfony.com/schema/dic/services
151+
http://symfony.com/schema/dic/services/services-1.0.xsd">
152+
153+
<services>
154+
155+
<service id="app.assets.buster_version_strategy" class="AppBundle\Asset\VersionStrategy\BusterVersionStrategy" public="false">
156+
<argument type="collection">
157+
<argument key="manifest_path">%kernel.root_dir%/../busters.json</argument>
158+
<argument key="format">%%s?version=%%s</argument>
159+
</argument>
160+
</service>
161+
162+
</services>
163+
</container>
164+
165+
.. code-block:: php
166+
167+
// app/config/services.php
168+
use Symfony\Component\DependencyInjection\Definition;
169+
170+
$definition = new Definition(
171+
'AppBundle\Asset\VersionStrategy\BusterVersionStrategy',
172+
array(
173+
array(
174+
'manifest_path' => '%kernel.root_dir%/../busters.json',
175+
'format' => '%%s?version=%%s',
176+
),
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 $for F438 mat;
204+
205+
/**
206+
* @var string[]
207+
*/
208+
private $hashes;
209+
210+
/**
211+
* @param array $options {
212+
* @var string $manifest_path
213+
* @var string|null $format
214+
* }
215+
*/
216+
public function __construct(array $options)
217+
{
218+
$this->manifestPath = $options['manifest_path'];
219+
$this->format = isset($options['format']) ? $options['format'] : '%s?%s';
220+
}
221+
222+
public function getVersion($path)
223+
{
224+
if (!is_array($this->hashes)) {
225+
$this->hashes = $this->loadManifest();
226+
}
227+
228+
return isset($this->hashes[$path]) ? $this->hashes[$path] : '';
229+
}
230+
231+
public function applyVersion($path)
232+
{
233+
$version = $this->getVersion($path);
234+
235+
if ('' === $version) {
236+
return $path;
237+
}
238+
239+
$versionized = sprintf($this->format, ltrim($path, '/'), $version);
240+
241+
if ($path && '/' === $path[0]) {
242+
return '/'.$versionized;
243+
}
244+
245+
return $versionized;
246+
}
247+
248+
private function loadManifest(array $options)
249+
{
250+
$hashes = json_decode(
251+
file_get_contents(realpath($this->manifestPath)),
252+
$assoc = true
253+
);
254+
255+
return $hashes;
256+
}
257+
}
258+
259+
.. _`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 10000 +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