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

liip / LiipImagineBundle / 22195007802

19 Feb 2026 06:37PM UTC coverage: 80.561% (+0.4%) from 80.126%
22195007802

Pull #1651

github

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

150 of 167 new or added lines in 7 files covered. (89.82%)

16 existing lines in 3 files now uncovered.

2296 of 2850 relevant lines covered (80.56%)

94.77 hits per line

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

97.54
/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;
352✔
43
        $this->loadersFactories = $loadersFactories;
352✔
44
    }
45

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

51
        $rootNode
341✔
52
            ->beforeNormalization()
341✔
53
                ->always(function ($v) {
341✔
54
                    if (\is_array($v) && \array_key_exists('webp', $v)) {
319✔
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
                    return $v;
319✔
65
                })
341✔
66
            ->end();
341✔
67

68
        $resolversPrototypeNode = $rootNode
341✔
69
            ->children()
341✔
70
                ->arrayNode('resolvers')
341✔
71
                    ->useAttributeAsKey('name')
341✔
72
                    ->prototype('array')
341✔
73
                        ->performNoDeepMerging();
341✔
74
        $this->addResolversSections($resolversPrototypeNode);
341✔
75

76
        $loadersPrototypeNode = $rootNode
341✔
77
            ->children()
341✔
78
                ->arrayNode('loaders')
341✔
79
                    ->useAttributeAsKey('name')
341✔
80
                    ->prototype('array');
341✔
81
        $this->addLoadersSections($loadersPrototypeNode);
341✔
82

83
        $rootNode
341✔
84
            ->beforeNormalization()
341✔
85
                ->ifTrue(function ($v) {
341✔
86
                    return
319✔
87
                        empty($v['loaders'])
319✔
88
                        || empty($v['loaders']['default'])
319✔
89
                        || empty($v['resolvers'])
319✔
90
                        || empty($v['resolvers']['default']);
319✔
91
                })
341✔
92
                ->then(function ($v) {
341✔
93
                    if (empty($v['loaders'])) {
319✔
94
                        $v['loaders'] = [];
275✔
95
                    }
96

97
                    if (false === \is_array($v['loaders'])) {
319✔
98
                        throw new \LogicException('Loaders has to be array');
11✔
99
                    }
100

101
                    if (false === \array_key_exists('default', $v['loaders'])) {
308✔
102
                        $v['loaders']['default'] = ['filesystem' => null];
297✔
103
                    }
104

105
                    if (empty($v['resolvers'])) {
308✔
106
                        $v['resolvers'] = [];
264✔
107
                    }
108

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

113
                    if (false === \array_key_exists('default', $v['resolvers'])) {
297✔
114
                        $v['resolvers']['default'] = ['web_path' => null];
286✔
115
                    }
116

117
                    return $v;
297✔
118
                })
341✔
119
            ->end();
341✔
120

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

UNCOV
250
                                return $v;
×
251
                            })
341✔
252
                        ->end()
341✔
253
                    ->end()
341✔
254
                    ->scalarNode('assets_version')->defaultNull()->end()
341✔
255
                ->end()
341✔
256
            ->end()
341✔
257
            ->booleanNode('enqueue')
341✔
258
                ->defaultFalse()
341✔
259
                ->info('Enables integration with enqueue if set true. Allows resolve image caches in background by sending messages to MQ.')
341✔
260
            ->end()
341✔
261
            ->arrayNode('messenger')
341✔
262
                ->canBeEnabled()
341✔
263
                ->info('Enables integration with symfony/messenger if set true. Warmup image caches in background by sending messages to MQ.')
341✔
264
            ->end()
341✔
265
            ->booleanNode('templating')
341✔
266
                ->defaultTrue()
341✔
267
                ->info('Enables integration with symfony/templating component')
341✔
268
                ->validate()
341✔
269
                    ->ifTrue()
341✔
270
                    ->then(function ($v) {
341✔
271
                        @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✔
272

273
                        return $v;
11✔
274
                    })
341✔
275
                ->end()
341✔
276
            ->end()
341✔
277
        ->end();
341✔
278

279
        $rootNode
341✔
280
            ->children()
341✔
281
                ->arrayNode('webp')
341✔
282
                    ->setDeprecated('liip/imagine-bundle', '2.x', 'The "webp" option is deprecated and will be removed in 3.0. Use "alternative_formats" instead.')
341✔
283
                    ->children()
341✔
284
                        ->booleanNode('generate')->defaultFalse()->end()
341✔
285
                        ->integerNode('quality')->defaultValue(100)->end()
341✔
286
                        ->scalarNode('cache')->defaultNull()->end()
341✔
287
                        ->scalarNode('data_loader')->defaultNull()->end()
341✔
288
                        ->arrayNode('post_processors')
341✔
289
                            ->defaultValue([])
341✔
290
                            ->useAttributeAsKey('name')
341✔
291
                            ->prototype('array')
341✔
292
                                ->useAttributeAsKey('name')
341✔
293
                                ->ignoreExtraKeys(false)
341✔
294
                                ->prototype('variable')->end()
341✔
295
                            ->end()
341✔
296
                    ->end()
341✔
297
                ->end()
341✔
298
            ->end();
341✔
299

300
        return $treeBuilder;
341✔
301
    }
302

303
    private function addResolversSections(ArrayNodeDefinition $resolversPrototypeNode)
304
    {
305
        $this->addConfigurationSections($this->resolversFactories, $resolversPrototypeNode, 'resolver');
341✔
306
    }
307

308
    private function addLoadersSections(ArrayNodeDefinition $resolversPrototypeNode)
309
    {
310
        $this->addConfigurationSections($this->loadersFactories, $resolversPrototypeNode, 'loader');
341✔
311
    }
312

313
    /**
314
     * @param FactoryInterface[] $factories
315
     */
316
    private function addConfigurationSections(array $factories, ArrayNodeDefinition $definition, $type)
317
    {
318
        foreach ($factories as $f) {
341✔
319
            $f->addConfiguration($definition->children()->arrayNode($f->getName()));
319✔
320
        }
321

322
        $definition->end()
341✔
323
            ->validate()
341✔
324
            ->ifTrue(function ($array) use ($type) {
341✔
325
                foreach ($array as $name => $element) {
286✔
326
                    if (!$element) {
286✔
UNCOV
327
                        throw new InvalidConfigurationException(ucfirst($type).' "'.$name.'" must have a factory configured');
×
328
                    }
329
                }
330

331
                return false;
286✔
332
            })
341✔
333
            ->thenInvalid('Each '.$type.' must have a factory configured')
341✔
334
            ->end();
341✔
335
    }
336
}
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