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

liip / LiipImagineBundle / 22198012024

19 Feb 2026 08:04PM UTC coverage: 81.034% (+0.9%) from 80.126%
22198012024

Pull #1651

github

web-flow
Merge 5909f3aa5 into 69d2df3c6
Pull Request #1651: Deprecate `webp` configuration in favor of `alternative_formats` and …

221 of 238 new or added lines in 8 files covered. (92.86%)

16 existing lines in 3 files now uncovered.

2367 of 2921 relevant lines covered (81.03%)

98.33 hits per line

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

97.62
/DependencyInjection/Configuration.php
1
<?php
2

3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11

12
namespace Liip\ImagineBundle\DependencyInjection;
13

14
use Liip\ImagineBundle\Config\Controller\ControllerConfig;
15
use Liip\ImagineBundle\Controller\ImagineController;
16
use Liip\ImagineBundle\DependencyInjection\Factory\FactoryInterface;
17
use Liip\ImagineBundle\DependencyInjection\Factory\Loader\LoaderFactoryInterface;
18
use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\ResolverFactoryInterface;
19
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
20
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
21
use Symfony\Component\Config\Definition\ConfigurationInterface;
22
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
23

24
class Configuration implements ConfigurationInterface
25
{
26
    /**
27
     * @var ResolverFactoryInterface[]
28
     */
29
    protected $resolversFactories;
30

31
    /**
32
     * @var LoaderFactoryInterface[]
33
     */
34
    protected $loadersFactories;
35

36
    /**
37
     * @param ResolverFactoryInterface[] $resolversFactories
38
     * @param LoaderFactoryInterface[]   $loadersFactories
39
     */
40
    public function __construct(array $resolversFactories, array $loadersFactories)
41
    {
42
        $this->resolversFactories = $resolversFactories;
374✔
43
        $this->loadersFactories = $loadersFactories;
374✔
44
    }
45

46
    public function getConfigTreeBuilder(): TreeBuilder
47
    {
48
        $treeBuilder = new TreeBuilder('liip_imagine');
363✔
49
        $rootNode = $treeBuilder->getRootNode();
363✔
50

51
        $rootNode
363✔
52
            ->beforeNormalization()
363✔
53
                ->always(function ($v) {
363✔
54
                    if (\is_array($v) && \array_key_exists('webp', $v)) {
341✔
55
                        if (!\array_key_exists('alternative_formats', $v)) {
33✔
56
                            $v['alternative_formats'] = [];
33✔
57
                        }
58
                        if (!\array_key_exists('webp', $v['alternative_formats'])) {
33✔
59
                            $v['alternative_formats']['webp'] = $v['webp'];
33✔
60
                        }
61
                        unset($v['webp']);
33✔
62
                    }
63

64
                    if (\is_array($v) && \array_key_exists('alternative_formats', $v)) {
341✔
65
                        $defaults = [
66✔
66
                            'webp' => ['image/webp'],
66✔
67
                            'avif' => ['image/avif'],
66✔
68
                        ];
66✔
69
                        foreach ($v['alternative_formats'] as $format => &$config) {
66✔
70
                            if (isset($defaults[$format]) && (empty($config['mime_types']) || !\is_array($config['mime_types']))) {
66✔
71
                                $config['mime_types'] = $defaults[$format];
55✔
72
                            }
73
                        }
74
                    }
75

76
                    return $v;
341✔
77
                })
363✔
78
            ->end();
363✔
79

80
        $resolversPrototypeNode = $rootNode
363✔
81
            ->children()
363✔
82
                ->arrayNode('resolvers')
363✔
83
                    ->useAttributeAsKey('name')
363✔
84
                    ->prototype('array')
363✔
85
                        ->performNoDeepMerging();
363✔
86
        $this->addResolversSections($resolversPrototypeNode);
363✔
87

88
        $loadersPrototypeNode = $rootNode
363✔
89
            ->children()
363✔
90
                ->arrayNode('loaders')
363✔
91
                    ->useAttributeAsKey('name')
363✔
92
                    ->prototype('array');
363✔
93
        $this->addLoadersSections($loadersPrototypeNode);
363✔
94

95
        $rootNode
363✔
96
            ->beforeNormalization()
363✔
97
                ->ifTrue(function ($v) {
363✔
98
                    return
341✔
99
                        empty($v['loaders'])
341✔
100
                        || empty($v['loaders']['default'])
341✔
101
                        || empty($v['resolvers'])
341✔
102
                        || empty($v['resolvers']['default']);
341✔
103
                })
363✔
104
                ->then(function ($v) {
363✔
105
                    if (empty($v['loaders'])) {
341✔
106
                        $v['loaders'] = [];
297✔
107
                    }
108

109
                    if (false === \is_array($v['loaders'])) {
341✔
110
                        throw new \LogicException('Loaders has to be array');
11✔
111
                    }
112

113
                    if (false === \array_key_exists('default', $v['loaders'])) {
330✔
114
                        $v['loaders']['default'] = ['filesystem' => null];
319✔
115
                    }
116

117
                    if (empty($v['resolvers'])) {
330✔
118
                        $v['resolvers'] = [];
286✔
119
                    }
120

121
                    if (false === \is_array($v['resolvers'])) {
330✔
122
                        throw new \LogicException('Resolvers has to be array');
11✔
123
                    }
124

125
                    if (false === \array_key_exists('default', $v['resolvers'])) {
319✔
126
                        $v['resolvers']['default'] = ['web_path' => null];
308✔
127
                    }
128

129
                    return $v;
319✔
130
                })
363✔
131
            ->end();
363✔
132

133
        $rootNode
363✔
134
            ->fixXmlConfig('filter_set', 'filter_sets')
363✔
135
            ->children()
363✔
136
                ->scalarNode('driver')->defaultValue('gd')
363✔
137
                    ->validate()
363✔
138
                        ->ifTrue(function ($v) {
363✔
139
                            return !\in_array($v, ['gd', 'imagick', 'gmagick', 'vips'], true);
×
140
                        })
363✔
141
                        ->thenInvalid('Invalid imagine driver specified: %s')
363✔
142
                    ->end()
363✔
143
                ->end()
363✔
144
                ->scalarNode('cache')->defaultValue('default')->end()
363✔
145
                ->scalarNode('cache_base_path')->defaultValue('')->end()
363✔
146
                ->scalarNode('data_loader')->defaultValue('default')->end()
363✔
147
                ->scalarNode('default_image')->defaultNull()->end()
363✔
148
                ->arrayNode('default_filter_set_settings')
363✔
149
                    ->addDefaultsIfNotSet()
363✔
150
                    ->children()
363✔
151
                        ->scalarNode('quality')->defaultValue(100)->end()
363✔
152
                        ->scalarNode('jpeg_quality')->defaultNull()->end()
363✔
153
                        ->scalarNode('png_compression_level')->defaultNull()->end()
363✔
154
                        ->scalarNode('png_compression_filter')->defaultNull()->end()
363✔
155
                        ->scalarNode('format')->defaultNull()->end()
363✔
156
                        ->booleanNode('animated')->defaultFalse()->end()
363✔
157
                        ->scalarNode('cache')->defaultNull()->end()
363✔
158
                        ->scalarNode('data_loader')->defaultNull()->end()
363✔
159
                        ->scalarNode('default_image')->defaultNull()->end()
363✔
160
                        ->arrayNode('filters')
363✔
161
                            ->useAttributeAsKey('name')
363✔
162
                            ->prototype('array')
363✔
163
                                ->useAttributeAsKey('name')
363✔
164
                                ->ignoreExtraKeys(false)
363✔
165
                                ->prototype('variable')->end()
363✔
166
                            ->end()
363✔
167
                        ->end()
363✔
168
                        ->arrayNode('post_processors')
363✔
169
                            ->defaultValue([])
363✔
170
                            ->useAttributeAsKey('name')
363✔
171
                            ->prototype('array')
363✔
172
                                ->useAttributeAsKey('name')
363✔
173
                                ->ignoreExtraKeys(false)
363✔
174
                                ->prototype('variable')->end()
363✔
175
                            ->end()
363✔
176
                        ->end()
363✔
177
                    ->end()
363✔
178
                ->end()
363✔
179
                ->arrayNode('controller')
363✔
180
                    ->addDefaultsIfNotSet()
363✔
181
                    ->children()
363✔
182
                        ->scalarNode('filter_action')->defaultValue(\sprintf('%s::filterAction', ImagineController::class))->end()
363✔
183
                        ->scalarNode('filter_runtime_action')->defaultValue(\sprintf('%s::filterRuntimeAction', ImagineController::class))->end()
363✔
184
                        ->integerNode('redirect_response_code')->defaultValue(302)
363✔
185
                            ->validate()
363✔
186
                                ->ifTrue(function ($redirectResponseCode) {
363✔
187
                                    return !\in_array($redirectResponseCode, ControllerConfig::REDIRECT_RESPONSE_CODES, true);
×
188
                                })
363✔
189
                                ->thenInvalid('Invalid redirect response code "%s" (must be 201, 301, 302, 303, 307, or 308).')
363✔
190
                            ->end()
363✔
191
                        ->end()
363✔
192
                    ->end()
363✔
193
                ->end()
363✔
194
                ->arrayNode('filter_sets')
363✔
195
                    ->useAttributeAsKey('name')
363✔
196
                    ->prototype('array')
363✔
197
                        ->fixXmlConfig('filter', 'filters')
363✔
198
                        ->children()
363✔
199
                            ->scalarNode('quality')->end()
363✔
200
                            ->scalarNode('jpeg_quality')->end()
363✔
201
                            ->scalarNode('png_compression_level')->end()
363✔
202
                            ->scalarNode('png_compression_filter')->end()
363✔
203
                            ->scalarNode('format')->end()
363✔
204
                            ->booleanNode('animated')->end()
363✔
205
                            ->scalarNode('cache')->end()
363✔
206
                            ->scalarNode('data_loader')->end()
363✔
207
                            ->scalarNode('default_image')->end()
363✔
208
                            ->arrayNode('filters')
363✔
209
                                ->useAttributeAsKey('name')
363✔
210
                                ->prototype('array')
363✔
211
                                    ->useAttributeAsKey('name')
363✔
212
                                    ->ignoreExtraKeys(false)
363✔
213
                                    ->prototype('variable')->end()
363✔
214
                                ->end()
363✔
215
                            ->end()
363✔
216
                            ->arrayNode('post_processors')
363✔
217
                                ->defaultValue([])
363✔
218
                                ->useAttributeAsKey('name')
363✔
219
                                ->prototype('array')
363✔
220
                                    ->useAttributeAsKey('name')
363✔
221
                                    ->ignoreExtraKeys(false)
363✔
222
                                    ->prototype('variable')->end()
363✔
223
                                ->end()
363✔
224
                        ->end()
363✔
225
                    ->end()
363✔
226
                ->end()
363✔
227
                ->end()
363✔
228
                ->arrayNode('alternative_formats')
363✔
229
                    ->useAttributeAsKey('format')
363✔
230
                    ->prototype('array')
363✔
231
                        ->children()
363✔
232
                            ->booleanNode('generate')->defaultFalse()->end()
363✔
233
                            ->integerNode('quality')->defaultValue(100)->end()
363✔
234
                            ->scalarNode('cache')->defaultNull()->end()
363✔
235
                            ->scalarNode('data_loader')->defaultNull()->end()
363✔
236
                            ->arrayNode('post_processors')
363✔
237
                                ->defaultValue([])
363✔
238
                                ->useAttributeAsKey('name')
363✔
239
                                ->prototype('variable')->end()
363✔
240
                            ->end()
363✔
241
                            ->arrayNode('mime_types')
363✔
242
                                ->prototype('scalar')->end()
363✔
243
                            ->end()
363✔
244
                            ->integerNode('priority')->defaultNull()->end()
363✔
245
                        ->end()
363✔
246
                    ->end()
363✔
247
                ->end()
363✔
248
        ->arrayNode('twig')
363✔
249
                ->addDefaultsIfNotSet()
363✔
250
                ->children()
363✔
251
                    ->enumNode('mode')
363✔
252
                        ->defaultValue('legacy')
363✔
253
                        ->info('Twig mode: none/lazy/legacy (default)')
363✔
254
                        ->values(['none', 'lazy', 'legacy'])
363✔
255
                        ->validate()
363✔
256
                            ->ifTrue(function ($v) {
363✔
UNCOV
257
                                return 'legacy' === $v;
×
258
                            })
363✔
259
                            ->then(function ($v) {
363✔
UNCOV
260
                                @trigger_error('Twig "legacy" mode has been deprecated and will be removed in 3.0. Use "none" or "lazy".', E_USER_DEPRECATED);
×
261

UNCOV
262
                                return $v;
×
263
                            })
363✔
264
                        ->end()
363✔
265
                    ->end()
363✔
266
                    ->scalarNode('assets_version')->defaultNull()->end()
363✔
267
                ->end()
363✔
268
            ->end()
363✔
269
            ->booleanNode('enqueue')
363✔
270
                ->defaultFalse()
363✔
271
                ->info('Enables integration with enqueue if set true. Allows resolve image caches in background by sending messages to MQ.')
363✔
272
            ->end()
363✔
273
            ->arrayNode('messenger')
363✔
274
                ->canBeEnabled()
363✔
275
                ->info('Enables integration with symfony/messenger if set true. Warmup image caches in background by sending messages to MQ.')
363✔
276
            ->end()
363✔
277
            ->booleanNode('templating')
363✔
278
                ->defaultTrue()
363✔
279
                ->info('Enables integration with symfony/templating component')
363✔
280
                ->validate()
363✔
281
                    ->ifTrue()
363✔
282
                    ->then(function ($v) {
363✔
283
                        @trigger_error('Symfony templating integration has been deprecated since LiipImagineBundle 2.2 and will be removed in 3.0. Use Twig and use "false" as "liip_imagine.templating" value instead.', E_USER_DEPRECATED);
11✔
284

285
                        return $v;
11✔
286
                    })
363✔
287
                ->end()
363✔
288
            ->end()
363✔
289
        ->end();
363✔
290

291
        $rootNode
363✔
292
            ->children()
363✔
293
                ->arrayNode('webp')
363✔
294
                    ->setDeprecated('liip/imagine-bundle', '2.x', 'The "webp" option is deprecated and will be removed in 3.0. Use "alternative_formats" instead.')
363✔
295
                    ->children()
363✔
296
                        ->booleanNode('generate')->defaultFalse()->end()
363✔
297
                        ->integerNode('quality')->defaultValue(100)->end()
363✔
298
                        ->scalarNode('cache')->defaultNull()->end()
363✔
299
                        ->scalarNode('data_loader')->defaultNull()->end()
363✔
300
                        ->arrayNode('post_processors')
363✔
301
                            ->defaultValue([])
363✔
302
                            ->useAttributeAsKey('name')
363✔
303
                            ->prototype('array')
363✔
304
                                ->useAttributeAsKey('name')
363✔
305
                                ->ignoreExtraKeys(false)
363✔
306
                                ->prototype('variable')->end()
363✔
307
                            ->end()
363✔
308
                    ->end()
363✔
309
                ->end()
363✔
310
            ->end();
363✔
311

312
        return $treeBuilder;
363✔
313
    }
314

315
    private function addResolversSections(ArrayNodeDefinition $resolversPrototypeNode)
316
    {
317
        $this->addConfigurationSections($this->resolversFactories, $resolversPrototypeNode, 'resolver');
363✔
318
    }
319

320
    private function addLoadersSections(ArrayNodeDefinition $resolversPrototypeNode)
321
    {
322
        $this->addConfigurationSections($this->loadersFactories, $resolversPrototypeNode, 'loader');
363✔
323
    }
324

325
    /**
326
     * @param FactoryInterface[] $factories
327
     */
328
    private function addConfigurationSections(array $factories, ArrayNodeDefinition $definition, $type)
329
    {
330
        foreach ($factories as $f) {
363✔
331
            $f->addConfiguration($definition->children()->arrayNode($f->getName()));
341✔
332
        }
333

334
        $definition->end()
363✔
335
            ->validate()
363✔
336
            ->ifTrue(function ($array) use ($type) {
363✔
337
                foreach ($array as $name => $element) {
308✔
338
                    if (!$element) {
308✔
UNCOV
339
                        throw new InvalidConfigurationException(ucfirst($type).' "'.$name.'" must have a factory configured');
×
340
                    }
341
                }
342

343
                return false;
308✔
344
            })
363✔
345
            ->thenInvalid('Each '.$type.' must have a factory configured')
363✔
346
            ->end();
363✔
347
    }
348
}
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