Как использовать стратегию пользовательских версий для ресурсов

Вресионирование ресурсов - это техника, которая улучшает производительность веб-приложений, добавляя идентификатор версии к URL статических ресурсов (CSS, JavaScript, images, и др.). Когда содержимое ресурса изменяется, его идентификатор также изменяется, чтобы заставить браузер скачать его заново, вместо повторного использоваия кешрованного ресаурса.

Symfony поддерживает версионирование ресурсов благодаря опциям конфигурации version и version_format. Если ваше приложение требует более продвинутого версионирования, например, динамического генерирования версии, основанной на некоторой внешней информации, то выможете создать вашу собственную стратегию версии.

Создание собственной стратегии версии

Следующий пример показывает, как создать стратегию версии, совместимую с gulp-buster. Этот инструмент определяет файл конфигурации, под названием busters.json, который соединяет каждый файл ресурса с его хешем контента:

1
2
3
4
{
    "js/script.js": "f9c7afd05729f10f55b689f36bb20172",
    "css/style.css": "91cd067f79a5839536b46c494c4272d8"
}

Реализация VersionStrategyInterface

Стратегии версий ресурсов - это PHP-классы, которые реализуют VersionStrategyInterface. В этом примере, конструктор класса берёт в качестве аргументов путь к файлу манифеста, сгенерированного gulp-buster и формат сгенерированной строки версии:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// src/AppBundle/Asset/VersionStrategy/GulpBusterVersionStrategy.php
namespace AppBundle\Asset\VersionStrategy;

use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;

class GulpBusterVersionStrategy 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()
    {
        return json_decode(file_get_contents($this->manifestPath), true);
    }
}

Регистрация сервиса стратегии

После создания стратегии PHP-класса, зарегистрируйте его в качестве сервиса Symfony.

  • YAML
    1
    2
    3
    4
    5
    6
    7
    # app/config/services.yml
    services:
        AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy:
            arguments:
                - "%kernel.project_dir%/busters.json"
                - "%%s?version=%%s"
            public: false
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- app/config/services.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd"
    >
        <services>
            <service id="AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy" public="false">
                <argument>%kernel.project_dir%/busters.json</argument>
                <argument>%%s?version=%%s</argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // app/config/services.php
    use Symfony\Component\DependencyInjection\Definition;
    use AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy;
    
    $container->autowire(GulpBusterVersionStrategy::class)
        ->setArguments(
            array(
                '%kernel.project_dir%/busters.json',
                '%%s?version=%%s',
            )
    )->setPublic(false);
    

Наконец, подключите новое версионирование ресурсов для всех ресурсов приложения или только для некоторых пакетов ресурсовм, благодаря version_strategy option:

  • YAML
    1
    2
    3
    4
    5
    # app/config/config.yml
    framework:
        # ...
        assets:
            version_strategy: 'AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <framework:config>
            <framework:assets version-strategy="AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy" />
        </framework:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // app/config/config.php
    use AppBundle\Asset\VersionStrategy\GulpBusterVersionStrategy;
    
    $container->loadFromExtension('framework', array(
        // ...
        'assets' => array(
            'version_strategy' => GulpBusterVersionStrategy::class,
        ),
    ));
    

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.