Completed
Push — master ( 70065c...f2406b )
by Kevin
12:35 queued 10:57
created

Configuration   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 399
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 3

Test Coverage

Coverage 97.64%

Importance

Changes 0
Metric Value
wmc 13
lcom 0
cbo 3
dl 0
loc 399
ccs 331
cts 339
cp 0.9764
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
B getConfigTreeBuilder() 0 63 6
B createGroupsNode() 0 327 7
1
<?php
2
3
namespace Liip\MonitorBundle\DependencyInjection;
4
5
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
6
use Symfony\Component\Config\Definition\ConfigurationInterface;
7
8
/**
9
 * This class contains the configuration information for the bundle.
10
 *
11
 * This information is solely responsible for how the different configuration
12
 * sections are normalized, and merged.
13
 *
14
 * @author Lukas Kahwe Smith <[email protected]>
15
 */
16
class Configuration implements ConfigurationInterface
17
{
18
    /**
19
     * Generates the configuration tree.
20
     *
21
     * @return TreeBuilder
22
     */
23 49
    public function getConfigTreeBuilder()
24
    {
25 49
        $treeBuilder = new TreeBuilder('liip_monitor');
26
27
        // Keep compatibility with symfony/config < 4.2
28 49
        if (\method_exists($treeBuilder, 'getRootNode')) {
29 49
            $rootNode = $treeBuilder->getRootNode();
30
        } else {
31
            $rootNode = $treeBuilder->root('liip_monitor');
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Config...der\TreeBuilder::root() has been deprecated with message: since Symfony 4.3, pass the root name to the constructor instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
32
        }
33
34
        $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...
35 49
            ->beforeNormalization()
36
                ->always(function ($v) {
37 49
                    if (empty($v['default_group'])) {
38 49
                        $v['default_group'] = 'default';
39
                    }
40
41 49
                    if (isset($v['checks']) && is_array($v['checks']) && !isset($v['checks']['groups'])) {
42 40
                        $checks = $v['checks'];
43 40
                        unset($v['checks']);
44
45 40
                        $v['checks']['groups'][$v['default_group']] = $checks;
46
                    }
47
48 49
                    return $v;
49 49
                })
50 49
            ->end()
51 49
            ->children()
52 49
                ->booleanNode('enable_controller')->defaultFalse()->end()
53 49
                ->scalarNode('view_template')->defaultNull()->end()
54 49
                ->integerNode('failure_status_code')
55 49
                    ->min(100)->max(598)
56 49
                    ->defaultValue(502)
57 49
                ->end()
58 49
                ->arrayNode('mailer')
59 49
                    ->canBeEnabled()
60 49
                    ->children()
61 49
                        ->arrayNode('recipient')
62 49
                            ->isRequired()->requiresAtLeastOneElement()
63 49
                            ->prototype('scalar')->end()
64 49
                            ->beforeNormalization()
65 49
                                ->ifString()
66
                                ->then(function ($v) { return [$v]; })
67 49
                            ->end()
68 49
                        ->end()
69 49
                        ->scalarNode('sender')->isRequired()->cannotBeEmpty()->end()
70 49
                        ->scalarNode('subject')->isRequired()->cannotBeEmpty()->end()
71 49
                        ->booleanNode('send_on_warning')->defaultTrue()->end()
72 49
                    ->end()
73 49
                ->end()
74 49
                ->scalarNode('default_group')->defaultValue('default')->end()
75 49
                ->arrayNode('checks')
76 49
                    ->canBeUnset()
77 49
                    ->children()
78 49
                        ->append($this->createGroupsNode())
79 49
                    ->end()
80 49
                ->end()
81 49
            ->end()
82 49
        ->end();
83
84 49
        return $treeBuilder;
85
    }
86
87 49
    private function createGroupsNode()
88
    {
89 49
        $builder = new TreeBuilder('groups');
90
91
        // Keep compatibility with symfony/config < 4.2
92 49
        if (\method_exists($builder, 'getRootNode')) {
93 49
            $node = $builder->getRootNode();
94
        } else {
95
            $node = $builder->root('groups');
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Config...der\TreeBuilder::root() has been deprecated with message: since Symfony 4.3, pass the root name to the constructor instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
96
        }
97
        $node
98 49
            ->requiresAtLeastOneElement()
99 49
            ->info('Grouping checks')
100 49
            ->useAttributeAsKey('name')
101 49
            ->prototype('array')
102 49
                ->children()
103 49
                    ->arrayNode('php_extensions')
104 49
                        ->info('Validate that a named extension or a collection of extensions is available')
105 49
                        ->example('session.use_only_cookies: false')
106 49
                        ->prototype('scalar')->end()
107 49
                    ->end()
108 49
                    ->arrayNode('php_flags')
109 49
                        ->info('Pairs of a PHP setting and an expected value')
110 49
                        ->example('session.use_only_cookies: false')
111 49
                        ->useAttributeAsKey('setting')
112 49
                        ->prototype('scalar')->defaultValue(true)->end()
113 49
                    ->end()
114 49
                    ->arrayNode('php_version')
115 49
                        ->info('Pairs of a version and a comparison operator')
116 49
                        ->example('5.4.15: >=')
117 49
                        ->useAttributeAsKey('version')
118 49
                        ->prototype('scalar')->end()
119 49
                    ->end()
120 49
                    ->variableNode('process_running')
121 49
                        ->info('Process name/pid or an array of process names/pids')
122 49
                        ->example('[apache, foo]')
123 49
                    ->end()
124 49
                    ->arrayNode('readable_directory')
125 49
                        ->info('Validate that a given path (or a collection of paths) is a dir and is readable')
126 49
                        ->example('["%kernel.cache_dir%"]')
127 49
                        ->prototype('scalar')->end()
128 49
                    ->end()
129 49
                    ->arrayNode('writable_directory')
130 49
                        ->info('Validate that a given path (or a collection of paths) is a dir and is writable')
131 49
                        ->example('["%kernel.cache_dir%"]')
132 49
                        ->prototype('scalar')->end()
133 49
                    ->end()
134 49
                    ->arrayNode('class_exists')
135 49
                        ->info('Validate that a class or a collection of classes is available')
136 49
                        ->example('["Lua", "My\Fancy\Class"]')
137 49
                        ->prototype('scalar')->end()
138 49
                    ->end()
139 49
                    ->scalarNode('cpu_performance')
140 49
                        ->info('Benchmark CPU performance and return failure if it is below the given ratio')
141 49
                        ->example('1.0 # This is the power of an EC2 micro instance')
142 49
                    ->end()
143 49
                    ->arrayNode('disk_usage')
144 49
                        ->info('Checks to see if the disk usage is below warning/critical percent thresholds')
145 49
                        ->children()
146 49
                            ->integerNode('warning')->defaultValue(70)->end()
147 49
                            ->integerNode('critical')->defaultValue(90)->end()
148 49
                            ->scalarNode('path')->defaultValue('%kernel.cache_dir%')->end()
149 49
                        ->end()
150 49
                    ->end()
151 49
                    ->arrayNode('symfony_requirements')
152 49
                        ->info('Checks Symfony2 requirements file')
153 49
                        ->children()
154 49
                            ->scalarNode('file')->defaultValue('%kernel.root_dir%/SymfonyRequirements.php')->end()
155 49
                        ->end()
156 49
                    ->end()
157 49
                    ->arrayNode('opcache_memory')
158 49
                        ->info('Checks to see if the OpCache memory usage is below warning/critical thresholds')
159 49
                        ->children()
160 49
                            ->integerNode('warning')->defaultValue(70)->end()
161 49
                            ->integerNode('critical')->defaultValue(90)->end()
162 49
                        ->end()
163 49
                    ->end()
164 49
                    ->arrayNode('apc_memory')
165 49
                        ->info('Checks to see if the APC memory usage is below warning/critical thresholds')
166 49
                        ->children()
167 49
                            ->integerNode('warning')->defaultValue(70)->end()
168 49
                            ->integerNode('critical')->defaultValue(90)->end()
169 49
                        ->end()
170 49
                    ->end()
171 49
                    ->arrayNode('apc_fragmentation')
172 49
                        ->info('Checks to see if the APC fragmentation is below warning/critical thresholds')
173 49
                        ->children()
174 49
                            ->integerNode('warning')->defaultValue(70)->end()
175 49
                            ->integerNode('critical')->defaultValue(90)->end()
176 49
                        ->end()
177 49
                    ->end()
178 49
                    ->variableNode('doctrine_dbal')
179 49
                        ->defaultNull()
180 49
                        ->info('Connection name or an array of connection names')
181 49
                        ->example('[default, crm]')
182 49
                    ->end()
183 49
                    ->variableNode('doctrine_mongodb')
184 49
                        ->defaultNull()
185 49
                        ->info('Connection name or an array of connection names')
186 49
                        ->example('[default, crm]')
187 49
                    ->end()
188 49
                    ->arrayNode('doctrine_migrations')
189 49
                        ->useAttributeAsKey('name')
190 49
                        ->info('Checks to see if migrations from specified configuration file are applied')
191 49
                        ->prototype('array')
192 49
                            ->children()
193 49
                                ->scalarNode('configuration_file')
194 49
                                    ->info('Absolute path to doctrine migrations configuration')
195 49
                                ->end()
196 49
                                ->scalarNode('connection')
197 49
                                    ->isRequired()
198 49
                                    ->cannotBeEmpty()
199 49
                                    ->info('Connection name from doctrine DBAL configuration')
200 49
                                ->end()
201 49
                            ->end()
202 49
                            ->beforeNormalization()
203 49
                                ->ifString()
204
                                ->then(function ($value) {
205
                                    if (is_string($value)) {
206
                                        $value = ['connection' => $value];
207
                                    }
208
209
                                    return $value;
210 49
                                })
211 49
                            ->end()
212 49
                            ->validate()
213
                                ->always(function ($value) {
214
                                    if (is_array($value) && !isset($value['configuration_file']) && !class_exists('Doctrine\\Bundle\\MigrationsBundle\\Command\\DoctrineCommand')) {
215
                                        throw new \InvalidArgumentException('You should explicitly define "configuration_file" parameter or install doctrine/doctrine-migrations-bundle to use empty parameter.');
216
                                    }
217
218
                                    return $value;
219 49
                                })
220 49
                            ->end()
221 49
                        ->end()
222 49
                        ->example(
223
                            [
224
                                'application_migrations' => [
225 49
                                    'configuration_file' => '%kernel.root_dir%/Resources/config/migrations.yml',
226
                                    'connection' => 'default',
227
                                ],
228
                                'migrations_with_doctrine_bundle' => [
229
                                    'connection' => 'default',
230
                                ],
231
                                'migrations_with_doctrine_bundle_v2' => 'default',
232
                            ]
233
                        )
234 49
                    ->end()
235 49
                    ->arrayNode('memcache')
236 49
                        ->info('Check if MemCache extension is loaded and given server is reachable')
237 49
                        ->useAttributeAsKey('name')
238 49
                        ->prototype('array')
239 49
                            ->children()
240 49
                                ->scalarNode('host')->defaultValue('localhost')->end()
241 49
                                ->integerNode('port')->defaultValue(11211)->end()
242 49
                            ->end()
243 49
                        ->end()
244 49
                    ->end()
245 49
                    ->arrayNode('memcached')
246 49
                        ->info('Check if MemCached extension is loaded and given server is reachable')
247 49
                        ->useAttributeAsKey('name')
248 49
                        ->prototype('array')
249 49
                            ->children()
250 49
                                ->scalarNode('host')->defaultValue('localhost')->end()
251 49
                                ->integerNode('port')->defaultValue(11211)->end()
252 49
                            ->end()
253 49
                        ->end()
254 49
                    ->end()
255 49
                    ->arrayNode('redis')
256 49
                        ->info('Validate that a Redis service is running')
257 49
                        ->useAttributeAsKey('name')
258 49
                        ->beforeNormalization()
259 49
                            ->ifString()
260
                            ->then(function ($v) { return ['dsn' => $v]; })
261 49
                        ->end()
262 49
                        ->prototype('array')
263 49
                            ->children()
264 49
                                ->scalarNode('host')->defaultValue('localhost')->end()
265 49
                                ->integerNode('port')->defaultValue(6379)->end()
266 49
                                ->scalarNode('password')->defaultNull()->end()
267 49
                                ->scalarNode('dsn')->defaultNull()->end()
268 49
                            ->end()
269 49
                        ->end()
270 49
                    ->end()
271 49
                    ->arrayNode('http_service')
272 49
                        ->info('Attempt connection to given HTTP host and (optionally) check status code and page content')
273 49
                        ->useAttributeAsKey('name')
274 49
                        ->prototype('array')
275 49
                            ->children()
276 49
                                ->scalarNode('host')->defaultValue('localhost')->end()
277 49
                                ->integerNode('port')->defaultValue(80)->end()
278 49
                                ->scalarNode('path')->defaultValue('/')->end()
279 49
                                ->integerNode('status_code')->defaultValue(200)->end()
280 49
                                ->scalarNode('content')->defaultNull()->end()
281 49
                            ->end()
282 49
                        ->end()
283 49
                    ->end()
284 49
                    ->arrayNode('guzzle_http_service')
285 49
                        ->info('Attempt connection using Guzzle to given HTTP host and (optionally) check status code and page content')
286 49
                        ->useAttributeAsKey('name')
287 49
                        ->prototype('array')
288 49
                            ->children()
289 49
                                ->scalarNode('url')->defaultValue('localhost')->end()
290 49
                                ->variableNode('headers')->defaultValue([])->end()
291 49
                                ->variableNode('options')->defaultValue([])->end()
292 49
                                ->integerNode('status_code')->defaultValue(200)->end()
293 49
                                ->scalarNode('content')->defaultNull()->end()
294 49
                                ->scalarNode('method')->defaultValue('GET')->end()
295 49
                                ->scalarNode('body')->defaultNull()->end()
296 49
                            ->end()
297 49
                        ->end()
298 49
                    ->end()
299 49
                    ->arrayNode('rabbit_mq')
300 49
                        ->info('Validate that a RabbitMQ service is running')
301 49
                        ->useAttributeAsKey('name')
302 49
                        ->beforeNormalization()
303 49
                            ->ifString()
304
                            ->then(function ($v) { return ['dsn' => $v]; })
305 49
                        ->end()
306 49
                        ->prototype('array')
307 49
                            ->children()
308 49
                                ->scalarNode('host')->defaultValue('localhost')->end()
309 49
                                ->integerNode('port')->defaultValue(5672)->end()
310 49
                                ->scalarNode('user')->defaultValue('guest')->end()
311 49
                                ->scalarNode('password')->defaultValue('guest')->end()
312 49
                                ->scalarNode('vhost')->defaultValue('/')->end()
313 49
                                ->scalarNode('dsn')->defaultNull()->end()
314 49
                            ->end()
315 49
                        ->end()
316 49
                    ->end()
317 49
                    ->booleanNode('symfony_version')
318 49
                        ->info('Checks the version of this app against the latest stable release')
319 49
                    ->end()
320 49
                    ->arrayNode('custom_error_pages')
321 49
                        ->info('Checks if error pages have been customized for given error codes')
322 49
                        ->children()
323 49
                            ->arrayNode('error_codes')
324 49
                                ->isRequired()
325 49
                                ->requiresAtLeastOneElement()
326 49
                                ->prototype('scalar')->end()
327 49
                            ->end()
328 49
                            ->scalarNode('path')->defaultValue('%kernel.root_dir%')->end()
329 49
                            ->scalarNode('controller')->defaultValue('%twig.exception_listener.controller%')->end()
330 49
                        ->end()
331 49
                    ->end()
332 49
                    ->arrayNode('security_advisory')
333 49
                        ->info('Checks installed composer dependencies against the SensioLabs Security Advisory database')
334 49
                        ->children()
335 49
                            ->scalarNode('lock_file')->defaultValue('%kernel.root_dir%'.'/../composer.lock')->end()
336 49
                        ->end()
337 49
                    ->end()
338 49
                    ->arrayNode('stream_wrapper_exists')
339 49
                        ->info('Validate that a stream wrapper or collection of stream wrappers exists')
340 49
                        ->example('[\'zlib\', \'bzip2\', \'zip\']')
341 49
                        ->prototype('scalar')->end()
342 49
                    ->end()
343 49
                    ->arrayNode('file_ini')
344 49
                        ->info('Find and validate INI files')
345 49
                        ->example('[\'path/to/my.ini\']')
346 49
                        ->prototype('scalar')->end()
347 49
                    ->end()
348 49
                    ->arrayNode('file_json')
349 49
                        ->info('Find and validate JSON files')
350 49
                        ->example('[\'path/to/my.json\']')
351 49
                        ->prototype('scalar')->end()
352 49
                    ->end()
353 49
                    ->arrayNode('file_xml')
354 49
                        ->info('Find and validate XML files')
355 49
                        ->example('[\'path/to/my.xml\']')
356 49
                        ->prototype('scalar')->end()
357 49
                    ->end()
358 49
                    ->arrayNode('file_yaml')
359 49
                        ->info('Find and validate YAML files')
360 49
                        ->example('[\'path/to/my.yml\']')
361 49
                        ->prototype('scalar')->end()
362 49
                    ->end()
363 49
                    ->arrayNode('pdo_connections')
364 49
                        ->info('PDO connections to check for connection')
365 49
                        ->useAttributeAsKey('name')
366 49
                        ->prototype('array')
367 49
                            ->children()
368 49
                                ->scalarNode('dsn')->defaultNull()->end()
369 49
                                ->scalarNode('username')->defaultNull()->end()
370 49
                                ->scalarNode('password')->defaultNull()->end()
371 49
                                ->integerNode('timeout')->defaultValue(1)->end()
372 49
                            ->end()
373 49
                        ->end()
374 49
                    ->end()
375 49
                    ->arrayNode('expressions')
376 49
                        ->useAttributeAsKey('alias')
377 49
                        ->info('Checks that fail/warn when given expression is false (expressions are evaluated with symfony/expression-language)')
378 49
                        ->example([
379
                            'opcache' => [
380 49
                                'label' => 'OPcache',
381
                                'warning_expression' => "ini('opcache.revalidate_freq') > 0",
382
                                'critical_expression' => "ini('opcache.enable')",
383
                                'warning_message' => 'OPcache not optimized for production',
384
                                'critical_message' => 'OPcache not enabled',
385
                            ],
386
                        ])
387 49
                        ->prototype('array')
388 49
                            ->addDefaultsIfNotSet()
389 49
                            ->validate()
390
                                ->ifTrue(function ($value) {
391 2
                                    return !$value['warning_expression'] && !$value['critical_expression'];
392 49
                                })
393 49
                                ->thenInvalid('A warning_expression or a critical_expression must be set.')
394 49
                            ->end()
395 49
                            ->children()
396 49
                                ->scalarNode('label')->isRequired()->end()
397 49
                                ->scalarNode('warning_expression')
398 49
                                ->defaultNull()
399 49
                                ->example('ini(\'apc.stat\') == 0')
400 49
                            ->end()
401 49
                            ->scalarNode('critical_expression')
402 49
                            ->defaultNull()
403 49
                            ->example('ini(\'short_open_tag\') == 1')
404 49
                        ->end()
405 49
                        ->scalarNode('warning_message')->defaultNull()->end()
406 49
                        ->scalarNode('critical_message')->defaultNull()->end()
407 49
                    ->end()
408 49
                ->end()
409 49
            ->end()
410
        ;
411
412 49
        return $node;
413
    }
414
}
415