Completed
Push — ezp25003-trash_subitems_count_... ( c4ee15...9f71a1 )
by
unknown
60:38 queued 26:57
created

Configuration::addImageMagickSection()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 45
Code Lines 31

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 45
rs 8.8571
cc 2
eloc 31
nc 1
nop 1
1
<?php
2
3
/**
4
 * File containing the Configuration class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 *
9
 * @version //autogentag//
10
 */
11
namespace eZ\Bundle\EzPublishCoreBundle\DependencyInjection;
12
13
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface;
14
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAccessAware\Configuration as SiteAccessConfiguration;
15
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\Suggestion\Collector\SuggestionCollectorInterface;
16
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
17
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
18
19
class Configuration extends SiteAccessConfiguration
20
{
21
    /**
22
     * @var \eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ParserInterface
23
     */
24
    private $mainConfigParser;
25
26
    /**
27
     * @var Configuration\Suggestion\Collector\SuggestionCollectorInterface
28
     */
29
    private $suggestionCollector;
30
31
    public function __construct(ParserInterface $mainConfigParser, SuggestionCollectorInterface $suggestionCollector)
32
    {
33
        $this->suggestionCollector = $suggestionCollector;
34
        $this->mainConfigParser = $mainConfigParser;
35
    }
36
37
    /**
38
     * Generates the configuration tree builder.
39
     *
40
     * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
41
     */
42
    public function getConfigTreeBuilder()
43
    {
44
        $treeBuilder = new TreeBuilder();
45
        $rootNode = $treeBuilder->root('ezpublish');
46
47
        $this->addRepositoriesSection($rootNode);
48
        $this->addSiteaccessSection($rootNode);
49
        $this->addImageMagickSection($rootNode);
50
        $this->addHttpCacheSection($rootNode);
51
        $this->addPageSection($rootNode);
52
        $this->addRouterSection($rootNode);
53
54
        // Delegate SiteAccess config to configuration parsers
55
        $this->mainConfigParser->addSemanticConfig($this->generateScopeBaseNode($rootNode));
56
57
        return $treeBuilder;
58
    }
59
60
    public function addRepositoriesSection(ArrayNodeDefinition $rootNode)
61
    {
62
        $rootNode
63
            ->children()
64
                ->arrayNode('repositories')
65
                    ->info('Content repositories configuration')
66
                    ->example(
67
                        array(
68
                            'main' => array(
69
                                'engine' => 'legacy',
70
                                'connection' => 'my_doctrine_connection_name',
71
                            ),
72
                        )
73
                    )
74
                    ->useAttributeAsKey('alias')
75
                    ->prototype('array')
76
                        ->beforeNormalization()
77
                            ->always(
78
                                // Handling deprecated structure by mapping it to new one
79
                                function ($v) {
80
                                    if (isset($v['storage'])) {
81
                                        return $v;
82
                                    }
83
84
                                    if (isset($v['engine'])) {
85
                                        $v['storage']['engine'] = $v['engine'];
86
                                        unset($v['engine']);
87
                                    }
88
89
                                    if (isset($v['connection'])) {
90
                                        $v['storage']['connection'] = $v['connection'];
91
                                        unset($v['connection']);
92
                                    }
93
94
                                    if (isset($v['config'])) {
95
                                        $v['storage']['config'] = $v['config'];
96
                                        unset($v['config']);
97
                                    }
98
99
                                    return $v;
100
                                }
101
                            )
102
                        ->end()
103
                        ->beforeNormalization()
104
                            ->always(
105
                                // Setting default values
106
                                function ($v) {
107
                                    if ($v === null) {
108
                                        $v = array();
109
                                    }
110
111
                                    if (!isset($v['storage'])) {
112
                                        $v['storage'] = array();
113
                                    }
114
115
                                    if (!isset($v['search'])) {
116
                                        $v['search'] = array();
117
                                    }
118
119
                                    return $v;
120
                                }
121
                            )
122
                        ->end()
123
                        ->children()
124
                            ->arrayNode('storage')
125
                                ->children()
126
                                    ->scalarNode('engine')
127
                                        ->defaultValue('%ezpublish.api.storage_engine.default%')
128
                                        ->info('The storage engine to use')
129
                                    ->end()
130
                                    ->scalarNode('connection')
131
                                        ->defaultNull()
132
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
133
                                    ->end()
134
                                    ->arrayNode('config')
135
                                        ->info('Arbitrary configuration options, supported by your storage engine')
136
                                        ->useAttributeAsKey('key')
137
                                        ->prototype('variable')->end()
138
                                    ->end()
139
                                ->end()
140
                            ->end()
141
                            ->arrayNode('search')
142
                                ->children()
143
                                    ->scalarNode('engine')
144
                                        ->defaultValue('%ezpublish.api.search_engine.default%')
145
                                        ->info('The search engine to use')
146
                                    ->end()
147
                                    ->scalarNode('connection')
148
                                        ->defaultNull()
149
                                        ->info('The connection name, if applicable (e.g. Doctrine connection name). If not set, the default connection will be used.')
150
                                    ->end()
151
                                    ->arrayNode('config')
152
                                        ->info('Arbitrary configuration options, supported by your search engine')
153
                                        ->useAttributeAsKey('key')
154
                                        ->prototype('variable')->end()
155
                                    ->end()
156
                                ->end()
157
                            ->end()
158
                        ->end()
159
                    ->end()
160
                ->end()
161
            ->end();
162
    }
163
164
    public function addSiteaccessSection(ArrayNodeDefinition $rootNode)
165
    {
166
        $rootNode
167
            ->children()
168
                ->arrayNode('siteaccess')
169
                    ->info('SiteAccess configuration')
170
                    ->children()
171
                        ->arrayNode('list')
172
                            ->info('Available SiteAccess list')
173
                            ->example(array('ezdemo_site', 'ezdemo_site_admin'))
174
                            ->isRequired()
175
                            ->requiresAtLeastOneElement()
176
                            ->prototype('scalar')->end()
177
                        ->end()
178
                        ->arrayNode('groups')
179
                            ->useAttributeAsKey('key')
180
                            ->info('SiteAccess groups. Useful to share settings between Siteaccess')
181
                            ->example(array('ezdemo_group' => array('ezdemo_site', 'ezdemo_site_admin')))
182
                            ->prototype('array')
183
                                ->requiresAtLeastOneElement()
184
                                ->prototype('scalar')->end()
185
                            ->end()
186
                        ->end()
187
                        ->scalarNode('default_siteaccess')->isRequired()->info('Name of the default siteaccess')->end()
188
                        ->arrayNode('match')
189
                            ->info('Siteaccess match configuration. First key is the matcher class, value is passed to the matcher. Key can be a service identifier (prepended by "@"), or a FQ class name (prepended by "\\")')
190
                            ->example(
191
                                array(
192
                                    'Map\\URI' => array(
193
                                        'foo' => 'ezdemo_site',
194
                                        'ezdemo_site' => 'ezdemo_site',
195
                                        'ezdemo_site_admin' => 'ezdemo_site_admin',
196
                                    ),
197
                                    'Map\\Host' => array(
198
                                        'ezpublish.dev' => 'ezdemo_site',
199
                                        'admin.ezpublish.dev' => 'ezdemo_site_admin',
200
                                    ),
201
                                    '\\My\\Custom\\Matcher' => array(
202
                                        'some' => 'configuration',
203
                                    ),
204
                                    '@my.custom.matcher' => array(
205
                                        'some' => 'other_configuration',
206
                                    ),
207
                                )
208
                            )
209
                            ->isRequired()
210
                            ->useAttributeAsKey('key')
211
                            ->normalizeKeys(false)
212
                            ->prototype('array')
213
                                ->useAttributeAsKey('key')
214
                                ->beforeNormalization()
215
                                    ->always(
216
                                        function ($v) {
217
                                            // Value passed to the matcher should always be an array.
218
                                            // If value is not an array, we transform it to a hash, with 'value' as key.
219
                                            if (!is_array($v)) {
220
                                                return array('value' => $v);
221
                                            }
222
223
                                            // If passed value is a numerically indexed array, we must convert it into a hash.
224
                                            // See https://jira.ez.no/browse/EZP-21876
225
                                            if (array_keys($v) === range(0, count($v) - 1)) {
226
                                                $final = array();
227
                                                foreach ($v as $i => $val) {
228
                                                    $final["i$i"] = $val;
229
                                                }
230
231
                                                return $final;
232
                                            }
233
234
                                            return $v;
235
                                        }
236
                                    )
237
                                ->end()
238
                                ->normalizeKeys(false)
239
                                ->prototype('variable')->end()
240
                            ->end()
241
                        ->end()
242
                    ->end()
243
                ->end()
244
                ->arrayNode('locale_conversion')
245
                    ->info('Locale conversion map between eZ Publish format (i.e. fre-FR) to POSIX (i.e. fr_FR). The key is the eZ Publish locale. Check locale.yml in EzPublishCoreBundle to see natively supported locales.')
246
                    ->example(array('fre-FR' => 'fr_FR'))
247
                    ->useAttributeAsKey('key')
248
                    ->normalizeKeys(false)
249
                    ->prototype('scalar')->end()
250
                ->end()
251
            ->end();
252
    }
253
254
    private function addImageMagickSection(ArrayNodeDefinition $rootNode)
255
    {
256
        $filtersInfo =
257
<<<EOT
258
DEPRECATED.
259
This is only used for legacy injection.
260
You may use imagick/gmagick liip_imagine bundle drivers.
261
262
Hash of filters to be used for your image variations config.
263
#   Key is the filter name, value is an argument passed to "convert" binary.
264
#   You can use numbered placeholders (aka input variables) that will be replaced by defined parameters in your image variations config
265
EOT;
266
267
        $rootNode
268
            ->children()
269
                ->arrayNode('imagemagick')
270
                    ->info('ImageMagick configuration')
271
                    ->children()
272
                        ->booleanNode('enabled')->defaultTrue()->end()
273
                        ->scalarNode('path')
274
                            ->info('Absolute path of ImageMagick / GraphicsMagick "convert" binary.')
275
                            ->beforeNormalization()
276
                                ->ifTrue(
277
                                    function ($v) {
278
                                        $basename = basename($v);
279
                                        // If there is a space in the basename, just drop it and everything after it.
280
                                        if (($wsPos = strpos($basename, ' ')) !== false) {
281
                                            $basename = substr($basename, 0, $wsPos);
282
                                        }
283
284
                                        return !is_executable(dirname($v) . DIRECTORY_SEPARATOR . $basename);
285
                                    }
286
                                )
287
                                ->thenInvalid('Please provide full path to ImageMagick / GraphicsMagick  "convert" binary. Please also check that it is executable.')
288
                            ->end()
289
                        ->end()
290
                        ->arrayNode('filters')
291
                            ->info($filtersInfo)
292
                            ->example(array('geometry/scaledownonly' => '"-geometry {1}x{2}>"'))
293
                            ->prototype('scalar')->end()
294
                        ->end()
295
                    ->end()
296
                ->end()
297
            ->end();
298
    }
299
300
    private function addHttpCacheSection(ArrayNodeDefinition $rootNode)
301
    {
302
        $purgeTypeInfo = <<<EOT
303
Http cache purge type.
304
305
Cache purge for content/locations is triggered when needed (e.g. on publish) and will result in one or several Http PURGE requests.
306
Can be "local" or "http" or a valid service ID:
307
- If "local" is used, an Http PURGE request will be emulated when needed (e.g. when using Symfony internal reverse proxy).
308
- If "http" is used, only one Http BAN request will be sent, with X-Location-Id header containing locationIds to ban.
309
  X-Location-Id consists in a Regexp containing locationIds to ban.
310
  Examples:
311
   - (123|456|789) => Purge locations #123, #456, #789.
312
   - .* => Purge all locations.
313
- If a serviceId is provided, it must be defined in the ServiceContainer and must implement eZ\Publish\Core\MVC\Symfony\Cache\PurgeClientInterface.
314
EOT;
315
316
        $rootNode
317
            ->children()
318
                ->arrayNode('http_cache')
319
                    ->children()
320
                        ->scalarNode('purge_type')
321
                            ->info($purgeTypeInfo)
322
                            ->defaultValue('local')
323
                            ->beforeNormalization()
324
                                ->ifTrue(
325
                                    function ($v) {
326
                                        $http = array('multiple_http' => true, 'single_http' => true);
327
328
                                        return isset($http[$v]);
329
                                    }
330
                                )
331
                                ->then(
332
                                    function () {
333
                                        return 'http';
334
                                    }
335
                                )
336
                            ->end()
337
                        ->end()
338
                        ->scalarNode('timeout')->info('DEPRECATED')->end()
339
                    ->end()
340
                ->end()
341
            ->end();
342
    }
343
344
    private function addPageSection(ArrayNodeDefinition $rootNode)
345
    {
346
        $pageInfo = <<<EOT
347
List of globally registered layouts and blocks used by the Page fieldtype
348
EOT;
349
350
        $rootNode
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
351
            ->children()
352
                ->arrayNode('ezpage')
353
                    ->info($pageInfo)
354
                    ->children()
355
                        ->arrayNode('layouts')
356
                            ->info('List of registered layouts, the key is the identifier of the layout')
357
                            ->useAttributeAsKey('key')
358
                            ->normalizeKeys(false)
359
                            ->prototype('array')
360
                                ->children()
361
                                    ->scalarNode('name')->isRequired()->info('Name of the layout')->end()
362
                                    ->scalarNode('template')->isRequired()->info('Template to use to render this layout')->end()
363
                                ->end()
364
                            ->end()
365
                        ->end()
366
                        ->arrayNode('blocks')
367
                            ->info('List of registered blocks, the key is the identifier of the block')
368
                            ->useAttributeAsKey('key')
369
                            ->normalizeKeys(false)
370
                            ->prototype('array')
371
                                ->children()
372
                                    ->scalarNode('name')->isRequired()->info('Name of the block')->end()
373
                                ->end()
374
                            ->end()
375
                        ->end()
376
                        ->arrayNode('enabledBlocks')
377
                            ->prototype('scalar')
378
                            ->end()
379
                            ->info('List of enabled blocks by default')
380
                        ->end()
381
                        ->arrayNode('enabledLayouts')
382
                            ->prototype('scalar')
383
                            ->end()
384
                            ->info('List of enabled layouts by default')
385
                        ->end()
386
                    ->end()
387
                ->end()
388
            ->end();
389
    }
390
391
    private function addRouterSection(ArrayNodeDefinition $rootNode)
392
    {
393
        $nonSAAwareInfo = <<<EOT
394
Route names that are not supposed to be SiteAccess aware, i.e. Routes pointing to asset generation (like assetic).
395
Note that you can just specify a prefix to match a selection of routes.
396
e.g. "_assetic_" will match "_assetic_*"
397
Defaults to ['_assetic_', '_wdt', '_profiler', '_configurator_']
398
EOT;
399
        $rootNode
400
            ->children()
401
                ->arrayNode('router')
402
                    ->children()
403
                        ->arrayNode('default_router')
404
                            ->children()
405
                                ->arrayNode('non_siteaccess_aware_routes')
406
                                    ->prototype('scalar')->end()
407
                                    ->info($nonSAAwareInfo)
408
                                    ->example(array('my_route_name', 'some_prefix_'))
409
                                ->end()
410
                            ->end()
411
                        ->end()
412
                    ->end()
413
                    ->info('Router related settings')
414
                ->end()
415
            ->end();
416
    }
417
}
418