• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tito10047 / progressive-image-bundle / 23349657191

20 Mar 2026 03:22PM UTC coverage: 90.385% (+0.1%) from 90.276%
23349657191

push

github

Jozef Mostka
fix path caching when custom filter is aplied

0 of 17 new or added lines in 3 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

893 of 988 relevant lines covered (90.38%)

344.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.0
/src/DependencyInjection/ProgressiveImageExtension.php
1
<?php
2

3
/*
4
 * This file is part of the Progressive Image Bundle.
5
 *
6
 * (c) Jozef Môstka <https://github.com/tito10047/progressive-image-bundle>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
namespace Tito10047\ProgressiveImageBundle\DependencyInjection;
13

14
use Liip\ImagineBundle\LiipImagineBundle;
15
use Symfony\Component\Config\FileLocator;
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
17
use Symfony\Component\DependencyInjection\Extension\Extension;
18
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
19
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
20
use Symfony\Component\DependencyInjection\Parameter;
21
use Symfony\Component\DependencyInjection\Reference;
22
use Tito10047\ProgressiveImageBundle\Command\GenerateCustomCssCommand;
23
use Tito10047\ProgressiveImageBundle\Controller\LiipImagineController;
24
use Tito10047\ProgressiveImageBundle\Event\TransparentImageCacheSubscriber;
25
use Tito10047\ProgressiveImageBundle\Modifier\BaseFilterModifier;
26
use Tito10047\ProgressiveImageBundle\Modifier\FilterModifierInterface;
27
use Tito10047\ProgressiveImageBundle\Modifier\ModifierInterface;
28
use Tito10047\ProgressiveImageBundle\Modifier\ModifierProvider;
29
use Tito10047\ProgressiveImageBundle\Resolver\AssetMapperResolver;
30
use Tito10047\ProgressiveImageBundle\Resolver\ChainResolver;
31
use Tito10047\ProgressiveImageBundle\Resolver\FileSystemResolver;
32
use Tito10047\ProgressiveImageBundle\Service\LiipImagineRuntimeConfigGenerator;
33
use Tito10047\ProgressiveImageBundle\Service\LiipImagineRuntimeConfigGeneratorInterface;
34
use Tito10047\ProgressiveImageBundle\Service\MetadataReader;
35
use Tito10047\ProgressiveImageBundle\Service\PreloadCollector;
36
use Tito10047\ProgressiveImageBundle\Service\ResponsiveAttributeGenerator;
37
use Tito10047\ProgressiveImageBundle\Twig\Components\Image;
38
use Tito10047\ProgressiveImageBundle\Twig\TransparentCacheExtension;
39
use Tito10047\ProgressiveImageBundle\UrlGenerator\LiipImagineResponsiveImageUrlGenerator;
40
use Tito10047\ProgressiveImageBundle\UrlGenerator\ResponsiveImageUrlGeneratorInterface;
41

42
final class ProgressiveImageExtension extends Extension implements PrependExtensionInterface
43
{
44
    public function getAlias(): string
45
    {
46
        return 'progressive_image';
750✔
47
    }
48

49
    public function prepend(ContainerBuilder $builder): void
50
    {
51
        $builder->prependExtensionConfig('framework', [
750✔
52
            'asset_mapper' => [
750✔
53
                'paths' => [
750✔
54
                    __DIR__.'/../../assets' => 'tito10047/progressive-image-bundle',
750✔
55
                ],
750✔
56
            ],
750✔
57
        ]);
750✔
58
        $builder->prependExtensionConfig('twig_component', [
750✔
59
            'defaults' => [
750✔
60
                'Tito10047\ProgressiveImageBundle\Twig\Components\\' => [
750✔
61
                    'template_directory' => '@ProgressiveImage/components/',
750✔
62
                    'name_prefix' => 'pgi',
750✔
63
                ],
750✔
64
            ],
750✔
65
        ]);
750✔
66

67
        $configs = $builder->getExtensionConfig($this->getAlias());
750✔
68
        $configs = $this->processConfiguration(new Configuration(), $configs);
750✔
69

70
        if (isset($configs['responsive_strategy']['breakpoints'])) {
750✔
71
            $breakpoints = $configs['responsive_strategy']['breakpoints'];
×
72
            $liipConfigs = $builder->getExtensionConfig('liip_imagine');
×
73

74
            $newFilterSets = [];
×
75
            foreach ($liipConfigs as $liipConfig) {
×
76
                if (isset($liipConfig['filter_sets'])) {
×
77
                    foreach ($liipConfig['filter_sets'] as $setName => $setConfig) {
×
78
                        foreach ($breakpoints as $breakpointName => $width) {
×
79
                            $newSetName = $setName.'_'.$breakpointName;
×
80
                            if (isset($newFilterSets[$newSetName])) {
×
81
                                continue;
×
82
                            }
83
                            $newSetConfig = $setConfig;
×
84

85
                            if (isset($newSetConfig['filters']['thumbnail']['size'])) {
×
86
                                [$origWidth, $origHeight] = $newSetConfig['filters']['thumbnail']['size'];
×
87
                                if ($origWidth > 0 && $origHeight > 0) {
×
88
                                    $ratio = $origHeight / $origWidth;
×
89
                                    $newHeight = (int) round($width * $ratio);
×
90
                                    $newSetConfig['filters']['thumbnail']['size'] = [$width, $newHeight];
×
91
                                } else {
92
                                    $newSetConfig['filters']['thumbnail']['size'] = [$width, $width];
×
93
                                }
94
                            }
95

96
                            $newFilterSets[$newSetName] = $newSetConfig;
×
97
                        }
98
                    }
99
                }
100
            }
101

102
            if (!empty($newFilterSets)) {
×
103
                $builder->prependExtensionConfig('liip_imagine', [
×
104
                    'filter_sets' => $newFilterSets,
×
105
                ]);
×
106
            }
107
        }
108
    }
109

110
    public function load(array $configs, ContainerBuilder $container): void
111
    {
112
        $configs = $this->processConfiguration(new Configuration(), $configs);
750✔
113

114
        if (!isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
750✔
115
            throw new \LogicException('The TwigBundle is not registered in your application. Try running "composer require symfony/twig-bundle".');
×
116
        }
117

118
        $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
750✔
119
        $loader->load('services.php');
750✔
120

121
        $this->configureResolvers($configs, $container);
750✔
122

123
        $driver = $configs['driver'] ?? 'gd';
750✔
124
        $analyzerId = match ($driver) {
750✔
125
            'imagick' => 'progressive_image.analyzer.imagick',
×
126
            'gd' => 'progressive_image.analyzer.gd',
750✔
127
            default => $driver,
×
128
        };
750✔
129

130
        $loaderId = $configs['loader'] ?? 'progressive_image.filesystem.loader';
750✔
131
        $cacheId = $configs['cache'] ?? 'cache.app';
750✔
132
        $imageCacheServiceId = $configs['image_cache_service'] ?? 'cache.app';
750✔
133
        $imageCacheEnabled = $configs['image_cache_enabled'] ?? false;
750✔
134
        $ttl = $configs['ttl'] ?? null;
750✔
135
        $retinaConfig = $configs['retina'] ?? ['enabled' => true, 'multipliers' => [1, 2]];
750✔
136
        $retina = $retinaConfig['enabled'] ?? true;
750✔
137
        $retinaMultipliers = $retinaConfig['multipliers'] ?? [1, 2];
750✔
138

139
        if (!$imageCacheEnabled) {
750✔
140
            $imageCacheServiceReference = null;
15✔
141
        } else {
142
            $imageCacheServiceReference = new Reference('progressive_image.image_cache_service');
735✔
143
        }
144

145
        $definition = $container->getDefinition(MetadataReader::class);
750✔
146
        $definition->setArgument('$analyzer', new Reference($analyzerId))
750✔
147
            ->setArgument('$loader', new Reference($loaderId))
750✔
148
            ->setArgument('$pathResolver', new Reference('progressive_image.resolver.default'))
750✔
149
            ->setArgument('$cache', new Reference($cacheId))
750✔
150
            ->setArgument('$ttl', $configs['ttl'] ?? null)
750✔
151
            ->setArgument('$fallbackPath', $configs['fallback_image'] ?? null)
750✔
152
        ;
750✔
153
        $container->setParameter('progressive_image.image_cache_enabled', $imageCacheEnabled);
750✔
154
        $container->setParameter('progressive_image.ttl', $ttl);
750✔
155
        $container->setParameter('progressive_image.image_configs', $configs['image_configs'] ?? []);
750✔
156
        $container->setParameter('progressive_image.responsive_strategy.ratios', $configs['responsive_strategy']['ratios'] ?? []);
750✔
157
        $container->setAlias('progressive_image.image_cache_service', $imageCacheServiceId);
750✔
158

159
        $container->register(TransparentCacheExtension::class)
750✔
160
            ->setArgument('$ttl', new Parameter('progressive_image.ttl'))
750✔
161
            ->setArgument('$cache', $imageCacheServiceReference)
750✔
162
            ->addTag('twig.extension')
750✔
163
        ;
750✔
164

165
        $container->register(TransparentImageCacheSubscriber::class)
750✔
166
            ->setArgument('$enabled', new Parameter('progressive_image.image_cache_enabled'))
750✔
167
            ->setArgument('$cache', $imageCacheServiceReference)
750✔
168
            ->setArgument('$ttl', new Parameter('progressive_image.ttl'))
750✔
169
            ->addTag('kernel.event_subscriber')
750✔
170
        ;
750✔
171

172
        $container->registerForAutoconfiguration(ModifierInterface::class)
750✔
173
            ->addTag('progressive_image.modifier');
750✔
174

175
        $container->registerForAutoconfiguration(FilterModifierInterface::class)
750✔
176
            ->addTag('pgi.filter_modifier');
750✔
177

178
        $container->register(ModifierProvider::class)
750✔
179
            ->setArgument('$modifiers', new \Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument('progressive_image.modifier'));
750✔
180

181
        $container->register(BaseFilterModifier::class)
750✔
182
            ->addTag('progressive_image.modifier', ['priority' => -100]);
750✔
183

184
        if (class_exists(LiipImagineBundle::class)) {
750✔
185
            $container->register(LiipImagineRuntimeConfigGenerator::class)
728✔
186
                ->setArgument('$filterConfiguration', new Reference('liip_imagine.filter.configuration'))
728✔
187
                ->setArgument('$imageConfigs', new Parameter('progressive_image.image_configs'));
728✔
188

189
            $container->register(LiipImagineResponsiveImageUrlGenerator::class)
728✔
190
                ->setArgument('$cacheManager', new Reference('liip_imagine.cache.manager'))
728✔
191
                ->setArgument('$router', new Reference('router'))
728✔
192
                ->setArgument('$uriSigner', new Reference('uri_signer'))
728✔
193
                ->setArgument('$runtimeConfigGenerator', new Reference(LiipImagineRuntimeConfigGenerator::class))
728✔
194
                ->setArgument('$filterConfiguration', new Reference('liip_imagine.filter.configuration'))
728✔
195
                ->setArgument('$requestStack', new Reference('request_stack'))
728✔
196
                ->setArgument('$webpGenerate', new Parameter('liip_imagine.webp.generate'))
728✔
197
                ->setPublic(true);
728✔
NEW
198
                        $container->register(LiipImagineController::class)
728✔
NEW
199
                                ->setArgument('$signer', new Reference('uri_signer'))
728✔
NEW
200
                                ->setArgument('$filterService', new Reference('liip_imagine.service.filter'))
728✔
NEW
201
                                ->setArgument('$dataManager', new Reference('liip_imagine.data.manager'))
728✔
NEW
202
                                ->setArgument('$filterConfiguration', new Reference('liip_imagine.filter.configuration'))
728✔
NEW
203
                                ->setArgument('$controllerConfig', new Reference('liip_imagine.controller.config'))
728✔
NEW
204
                                ->setArgument('$runtimeConfigGenerator', new Reference(LiipImagineRuntimeConfigGenerator::class))
728✔
NEW
205
                                ->setArgument('$metadataReader', new Reference(MetadataReader::class))
728✔
NEW
206
                                ->setArgument('$cache', $imageCacheServiceReference)
728✔
NEW
207
                                ->setPublic(true);
728✔
208

209
            $container->setAlias(ResponsiveImageUrlGeneratorInterface::class, LiipImagineResponsiveImageUrlGenerator::class)->setPublic(true);
728✔
210
            $container->setAlias(LiipImagineRuntimeConfigGeneratorInterface::class, LiipImagineRuntimeConfigGenerator::class)->setPublic(true);
728✔
211
        }
212
        $responsiveConfig = $configs['responsive_strategy'] ?? [];
750✔
213
        $generatorId = $responsiveConfig['generator'] ?? null;
750✔
214

215
        if ($generatorId || class_exists(LiipImagineBundle::class) || isset($responsiveConfig['grid'])) {
750✔
216
            if (!$generatorId && !class_exists(LiipImagineBundle::class)) {
750✔
217
                // We need some default URL generator if LiipImagine is not present but we want to use ResponsiveAttributeGenerator
218
                $container->register('progressive_image.url_generator.default', \Tito10047\ProgressiveImageBundle\UrlGenerator\DefaultResponsiveImageUrlGenerator::class)
22✔
219
                    ->setPublic(true);
22✔
220
                $container->setAlias(ResponsiveImageUrlGeneratorInterface::class, 'progressive_image.url_generator.default')->setPublic(true);
22✔
221
            }
222

223
            $container->register(ResponsiveAttributeGenerator::class, ResponsiveAttributeGenerator::class)
750✔
224
                ->setArgument('$gridConfig', $responsiveConfig['grid'] ?? [])
750✔
225
                ->setArgument('$ratioConfig', $responsiveConfig['ratios'] ?? [])
750✔
226
                ->setArgument('$retinaMultipliers', $retinaMultipliers)
750✔
227
                ->setArgument('$preloadCollector', new Reference(PreloadCollector::class))
750✔
228
                ->setArgument('$urlGenerator', $generatorId ? new Reference($generatorId) : new Reference(ResponsiveImageUrlGeneratorInterface::class))
750✔
229
                ->setArgument('$modifierProvider', new Reference(ModifierProvider::class))
750✔
230
                ->setPublic(true)
750✔
231
            ;
750✔
232
        }
233

234
        $container->register(GenerateCustomCssCommand::class)
750✔
235
            ->setArgument('$gridConfig', $responsiveConfig['grid'] ?? [])
750✔
236
            ->setArgument('$projectDir', new Parameter('kernel.project_dir'))
750✔
237
            ->addTag('console.command');
750✔
238

239
        $container->register(Image::class, Image::class)
750✔
240
            ->setArgument('$analyzer', new Reference(MetadataReader::class))
750✔
241
            ->setArgument('$pathDecorator', array_map(fn ($id) => new Reference($id), $configs['path_decorators'] ?? []))
750✔
242
            ->setArgument('$responsiveAttributeGenerator', $generatorId || class_exists(LiipImagineBundle::class) || isset($responsiveConfig['grid']) ? new Reference(ResponsiveAttributeGenerator::class) : null)
750✔
243
            ->setArgument('$preloadCollector', new Reference(PreloadCollector::class))
750✔
244
            ->setArgument('$framework', $configs['responsive_strategy']['grid']['framework'] ?? 'custom')
750✔
245
            ->setArgument('$defaultRetina', $retina)
750✔
246
            ->setShared(false)
750✔
247
            ->addTag('twig.component')
750✔
248
            ->setPublic(true);
750✔
249
    }
250

251
    /**
252
     * @param array<string, mixed> $config
253
     */
254
    private function configureResolvers(array $config, ContainerBuilder $container): void
255
    {
256
        $resolvers = $config['resolvers'] ?? [];
750✔
257
        foreach ($resolvers as $name => $resolverConfig) {
750✔
258
            $id = 'progressive_image.resolver.'.$name;
428✔
259

260
            if ('filesystem' === $resolverConfig['type']) {
428✔
261
                $container->register($id, FileSystemResolver::class)
428✔
262
                    ->setArgument('$roots', $resolverConfig['roots'] ?? ['%kernel.project_dir%/public'])
428✔
263
                    ->setArgument('$allowUnresolvable', $resolverConfig['allowUnresolvable'] ?? true)
428✔
264
                    ->setPublic(true);
428✔
265
            } elseif ('asset_mapper' === $resolverConfig['type']) {
15✔
266
                $container->register($id, AssetMapperResolver::class)
15✔
267
                    ->setArgument('$assetMapper', new Reference('asset_mapper'))
15✔
268
                    ->setPublic(true);
15✔
269
            } elseif ('chain' === $resolverConfig['type']) {
15✔
270
                $childResolvers = array_map(fn ($name) => new Reference('progressive_image.resolver.'.$name), $resolverConfig['resolvers'] ?? []);
15✔
271
                $container->register($id, ChainResolver::class)
15✔
272
                    ->setArgument('$resolvers', $childResolvers)
15✔
273
                    ->setPublic(true);
15✔
274
            }
275
        }
276

277
        $resolver = $config['resolver'] ?? 'default';
750✔
278

279
        if (isset($resolvers[$resolver])) {
750✔
280
            $container->setAlias('progressive_image.resolver.default', 'progressive_image.resolver.'.$resolver);
413✔
281
        } elseif (in_array($resolver, ['filesystem', 'asset_mapper'])) {
337✔
282
            $container->setAlias('progressive_image.resolver.default', 'progressive_image.resolver.'.$resolver);
×
283
        } elseif (!empty($resolvers) && 'default' === $resolver) {
337✔
284
            $firstResolver = array_key_first($resolvers);
15✔
285
            $container->setAlias('progressive_image.resolver.default', 'progressive_image.resolver.'.$firstResolver);
15✔
286
        } else {
287
            $container->register('progressive_image.resolver.default', FileSystemResolver::class)
322✔
288
                ->setArgument('$roots', ['%kernel.project_dir%/public'])
322✔
289
                ->setArgument('$allowUnresolvable', true);
322✔
290
        }
291
    }
292
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc