Completed
Pull Request — master (#141)
by Evgenij
01:43
created

LiipMonitorExtension   C

Complexity

Total Complexity 65

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 65
lcom 1
cbo 13
dl 0
loc 327
rs 5.5294
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
C load() 0 57 11
C setParameters() 0 67 32
B configureDoctrineMigrationsCheck() 0 26 6
A getPredefinedMigrations() 0 17 3
F createMigrationConfigurationService() 0 76 11
B createTemporaryConfiguration() 0 30 2

How to fix   Complexity   

Complex Class

Complex classes like LiipMonitorExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use LiipMonitorExtension, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Liip\MonitorBundle\DependencyInjection;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Driver\PDOSqlite\Driver;
7
use Doctrine\DBAL\Migrations\Configuration\AbstractFileConfiguration;
8
use Doctrine\DBAL\Migrations\Configuration\Configuration as MigrationConfiguration;
9
use Symfony\Component\Config\FileLocator;
10
use Symfony\Component\DependencyInjection\ContainerBuilder;
11
use Symfony\Component\DependencyInjection\DefinitionDecorator;
12
use Symfony\Component\DependencyInjection\Loader;
13
use Symfony\Component\DependencyInjection\Reference;
14
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
15
16
class LiipMonitorExtension extends Extension
17
{
18
    /**
19
     * Loads the services based on your application configuration.
20
     *
21
     * @param array            $configs
22
     * @param ContainerBuilder $container
23
     */
24
    public function load(array $configs, ContainerBuilder $container)
25
    {
26
        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
27
        $loader->load('runner.xml');
28
        $loader->load('helper.xml');
29
30
        $configuration = new Configuration();
31
        $config = $this->processConfiguration($configuration, $configs);
32
33
        if (null === $config['view_template']) {
34
            $config['view_template'] = __DIR__.'/../Resources/views/health/index.html.php';
35
        }
36
37
        if ($config['enable_controller']) {
38
            $container->setParameter(sprintf('%s.view_template', $this->getAlias()), $config['view_template']);
39
            $loader->load('controller.xml');
40
        }
41
42
        if ($config['mailer']['enabled']) {
43
            $loader->load('helper/swift_mailer.xml');
44
45
            foreach ($config['mailer'] as $key => $value) {
46
                $container->setParameter(sprintf('%s.mailer.%s', $this->getAlias(), $key), $value);
47
            }
48
        }
49
50
        $container->setParameter(sprintf('%s.default_group', $this->getAlias()), $config['default_group']);
51
52
        if (empty($config['checks'])) {
53
            return;
54
        }
55
56
        $checksLoaded = array();
57
        $containerParams = array();
58
        foreach ($config['checks']['groups'] as $group => $checks) {
59
            if (empty($checks)) {
60
                continue;
61
            }
62
63
            foreach ($checks as $check => $values) {
64
                if (empty($values)) {
65
                    continue;
66
                }
67
68
                $containerParams['groups'][$group][$check] = $values;
69
                $this->setParameters($container, $check, $group, $values);
70
71
                if (!in_array($check, $checksLoaded)) {
72
                    $loader->load('checks/'.$check.'.xml');
73
                    $checksLoaded[] = $check;
74
                }
75
            }
76
        }
77
78
        $container->setParameter(sprintf('%s.checks', $this->getAlias()), $containerParams);
79
        $this->configureDoctrineMigrationsCheck($container, $containerParams);
80
    }
81
82
    /**
83
     * @param ContainerBuilder $container
84
     * @param string           $checkName
85
     * @param string           $group
86
     * @param array            $values
87
     */
88
    private function setParameters(ContainerBuilder $container, $checkName, $group, $values)
89
    {
90
        $prefix = sprintf('%s.check.%s', $this->getAlias(), $checkName);
91
        switch ($checkName) {
92
            case 'class_exists':
93
            case 'cpu_performance':
94
            case 'php_extensions':
95
            case 'php_version':
96
            case 'php_flags':
97
            case 'readable_directory':
98
            case 'writable_directory':
99
            case 'process_running':
100
            case 'doctrine_dbal':
101
            case 'http_service':
102
            case 'guzzle_http_service':
103
            case 'memcache':
104
            case 'redis':
105
            case 'rabbit_mq':
106
            case 'stream_wrapper_exists':
107
            case 'file_ini':
108
            case 'file_json':
109
            case 'file_xml':
110
            case 'file_yaml':
111
            case 'expressions':
112
                $container->setParameter($prefix.'.'.$group, $values);
113
                continue;
114
115
            case 'symfony_version':
116
                continue;
117
118
            case 'opcache_memory':
119
                if (!class_exists('ZendDiagnostics\Check\OpCacheMemory')) {
120
                    throw new \InvalidArgumentException('Please require at least "v1.0.4" of "ZendDiagnostics"');
121
                }
122
                continue;
123
124
            case 'doctrine_migrations':
125
                if (!class_exists('ZendDiagnostics\Check\DoctrineMigration')) {
126
                    throw new \InvalidArgumentException('Please require at least "v1.0.6" of "ZendDiagnostics"');
127
                }
128
129
                if (!class_exists('Doctrine\Bundle\MigrationsBundle\Command\DoctrineCommand')) {
130
                    throw new \InvalidArgumentException('Please require at least "v1.0.0" of "DoctrineMigrationsBundle"');
131
                }
132
133
                if (!class_exists('Doctrine\DBAL\Migrations\Configuration\Configuration')) {
134
                    throw new \InvalidArgumentException('Please require at least "v1.1.0" of "Doctrine Migrations Library"');
135
                }
136
137
                $container->setParameter($prefix.'.'.$group, $values);
138
                continue;
139
140
            case 'pdo_connections':
141
                if (!class_exists('ZendDiagnostics\Check\PDOCheck')) {
142
                    throw new \InvalidArgumentException('Please require at least "v1.0.5" of "ZendDiagnostics"');
143
                }
144
                $container->setParameter($prefix.'.'.$group, $values);
145
                continue;
146
147
        }
148
149
        if (is_array($values)) {
150
            foreach ($values as $key => $value) {
151
                $container->setParameter($prefix.'.'.$key.'.'.$group, $value);
152
            }
153
        }
154
    }
155
156
    /**
157
     * Set up doctrine migration configuration services
158
     *
159
     * @param ContainerBuilder $container The container
160
     * @param array            $params    Container params
161
     *
162
     * @return void
163
     */
164
    private function configureDoctrineMigrationsCheck(ContainerBuilder $container, array $params)
165
    {
166
        if (!$container->hasDefinition('liip_monitor.check.doctrine_migrations') || !isset($params['groups'])) {
167
            return;
168
        }
169
170
        foreach ($params['groups'] as $groupName => $groupChecks) {
171
            if (!isset($groupChecks['doctrine_migrations'])) {
172
                continue;
173
            }
174
175
            $services = [];
176
            foreach ($groupChecks['doctrine_migrations'] as $key => $config) {
177
                $serviceConfiguration =
178
                    $this->createMigrationConfigurationService($container, $config['configuration_file'], $config[ 'connection' ]);
179
180
                $serviceId = sprintf('liip_monitor.check.doctrine_migrations.configuration.%s.%s', $groupName, $key);
181
                $container->setDefinition($serviceId, $serviceConfiguration);
182
183
                $services[$key] = $serviceId;
184
            }
185
186
            $parameter = sprintf('%s.check.%s.%s', $this->getAlias(), 'doctrine_migrations', $groupName);
187
            $container->setParameter($parameter, $services);
188
        }
189
    }
190
191
    /**
192
     * Return key-value array with migration version as key and class as a value defined in config file
193
     *
194
     * @param AbstractFileConfiguration $config Current configuration
195
     * @param Connection                $connection Fake connections
196
     *
197
     * @return array[]
198
     */
199
    private function getPredefinedMigrations(AbstractFileConfiguration $config, Connection $connection)
200
    {
201
        $result = array();
202
203
        $diff = new MigrationConfiguration($connection);
204
        $diff->setMigrationsNamespace($config->getMigrationsNamespace());
205
        $diff->setMigrationsDirectory($config->getMigrationsDirectory());
206
        foreach ($config->getMigrations() as $version) {
207
            $result[$version->getVersion()] = get_class($version->getMigration());
208
        }
209
210
        foreach ($diff->getAvailableVersions() as $version) {
211
            unset($result[$version]);
212
        }
213
214
        return $result;
215
    }
216
217
    /**
218
     * Creates migration configuration service definition
219
     *
220
     * @param ContainerBuilder $container      DI Container
221
     * @param string           $filename       File name with migration configuration
222
     * @param string           $connectionName Connection name for container service
223
     *
224
     * @return DefinitionDecorator
225
     */
226
    private function createMigrationConfigurationService(ContainerBuilder $container, $filename, $connectionName)
227
    {
228
        /** @var AbstractFileConfiguration $configuration */
229
        $connection    = new Connection([], new Driver()); // needed for correct migration loading
230
        $configuration = $this->createTemporaryConfiguration($container, $connection, $filename);
231
232
        $serviceConfiguration =
233
            new DefinitionDecorator('liip_monitor.check.doctrine_migrations.abstract_configuration');
234
        $serviceConfiguration->replaceArgument(
235
            0,
236
            new Reference(sprintf('doctrine.dbal.%s_connection', $connectionName))
237
        );
238
239
        if ($configuration->getMigrationsNamespace()) {
240
            $serviceConfiguration->addMethodCall(
241
                'setMigrationsNamespace',
242
                [ $configuration->getMigrationsNamespace() ]
243
            );
244
        }
245
246
        if ($configuration->getMigrationsTableName()) {
247
            $serviceConfiguration->addMethodCall(
248
                'setMigrationsTableName',
249
                [ $configuration->getMigrationsTableName() ]
250
            );
251
        }
252
253
        if ($configuration->getMigrationsColumnName()) {
254
            $serviceConfiguration->addMethodCall(
255
                'setMigrationsColumnName',
256
                [ $configuration->getMigrationsColumnName() ]
257
            );
258
        }
259
260
        if ($configuration->getName()) {
261
            $serviceConfiguration->addMethodCall('setName', [ $configuration->getName() ]);
262
        }
263
264
        if ($configuration->getMigrationsDirectory()) {
265
            $directory        = $configuration->getMigrationsDirectory();
266
            $pathPlaceholders = array('kernel.root_dir', 'kernel.cache_dir', 'kernel.logs_dir');
267
            foreach ($pathPlaceholders as $parameter) {
268
                $kernelDir = realpath($container->getParameter($parameter));
269
                if (strpos(realpath($directory), $kernelDir) === 0) {
270
                    $directory = str_replace($kernelDir, '%kernel.root_dir%', $directory);
271
                    break;
272
                }
273
            }
274
275
276
            $serviceConfiguration->addMethodCall(
277
                'setMigrationsDirectory',
278
                [ $directory ]
279
            );
280
        }
281
282
        /** @var AbstractFileConfiguration $diff */
283
        $versions = $this->getPredefinedMigrations($configuration, $connection);
284
        if ($versions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $versions of type array[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
285
            $serviceConfiguration->addMethodCall('registerMigrations', [ $versions ]);
286
        }
287
288
        $serviceConfiguration->addMethodCall('configure', []);
289
290
        if ($configuration->areMigrationsOrganizedByYear()) {
291
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYear', [ true ]);
292
293
            return $serviceConfiguration;
294
        } elseif ($configuration->areMigrationsOrganizedByYearAndMonth()) {
295
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYearAndMonth', [ true ]);
296
297
            return $serviceConfiguration;
298
        }
299
300
        return $serviceConfiguration;
301
    }
302
303
    /**
304
     * Creates in-memory migration configuration for setting up container service
305
     *
306
     * @param ContainerBuilder $container  The container
307
     * @param Connection       $connection Fake connection
308
     * @param string           $filename   Migrations configuration file
309
     *
310
     * @return AbstractFileConfiguration
311
     */
312
    private function createTemporaryConfiguration(ContainerBuilder $container, Connection $connection, $filename)
313
    {
314
        // -------
315
        // This part must be in sync with Doctrine\DBAL\Migrations\Tools\Console\Helper\ConfigurationHelper::loadConfig
316
        $map = [
317
            'xml'  => '\XmlConfiguration',
318
            'yaml' => '\YamlConfiguration',
319
            'yml'  => '\YamlConfiguration',
320
            'php'  => '\ArrayConfiguration',
321
            'json' => '\JsonConfiguration',
322
        ];
323
        // --------
324
325
        $filename = $container->getParameterBag()->resolveValue($filename);
326
        $info     = pathinfo($filename);
327
        // check we can support this file type
328
        if (empty($map[ $info[ 'extension' ] ])) {
329
            throw new \InvalidArgumentException('Given config file type is not supported');
330
        }
331
332
        $class = 'Doctrine\DBAL\Migrations\Configuration';
333
        $class .= $map[ $info[ 'extension' ] ];
334
        // -------
335
336
        /** @var AbstractFileConfiguration $configuration */
337
        $configuration = new $class($connection);
338
        $configuration->load($filename);
339
340
        return $configuration;
341
    }
342
}
343