Completed
Push — master ( 76a3d2...4d32cd )
by Kevin
06:13
created

LiipMonitorExtension::setParameters()   D

Complexity

Conditions 30
Paths 82

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 30.9

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 36
cts 40
cp 0.9
rs 4.1666
c 0
b 0
f 0
cc 30
nc 82
nop 4
crap 30.9

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Liip\MonitorBundle\DependencyInjection;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Driver\PDOSqlite\Driver;
7
use Doctrine\Migrations\Configuration\AbstractFileConfiguration;
8
use Doctrine\Migrations\Configuration\Configuration as DoctrineMigrationConfiguration;
9
use Doctrine\Migrations\MigrationException;
10
use Liip\MonitorBundle\DoctrineMigrations\Configuration as LiipMigrationConfiguration;
11
use Symfony\Component\Config\FileLocator;
12
use Symfony\Component\DependencyInjection\ChildDefinition;
13
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Definition;
16
use Symfony\Component\DependencyInjection\DefinitionDecorator;
17
use Symfony\Component\DependencyInjection\Loader;
18
use Symfony\Component\DependencyInjection\Reference;
19
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
20
21
class LiipMonitorExtension extends Extension implements CompilerPassInterface
22
{
23
    /**
24
     * Tuple (migrationsConfiguration, tempConfiguration) for doctrine migrations check.
25
     *
26
     * @var array
27
     */
28
    private $migrationConfigurationsServices = [];
29
30
    /**
31
     * Connection object needed for correct migration loading.
32
     *
33
     * @var Connection
34
     */
35
    private $fakeConnection;
36
37 49
    public function __construct()
38
    {
39 49
        if (class_exists(Connection::class)) {
40 49
            $this->fakeConnection = new Connection([], new Driver());
41
        }
42 49
    }
43
44
    /**
45
     * Loads the services based on your application configuration.
46
     */
47 49
    public function load(array $configs, ContainerBuilder $container)
48
    {
49 49
        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
50 49
        $loader->load('runner.xml');
51 49
        $loader->load('helper.xml');
52 49
        $loader->load('commands.xml');
53
54 49
        $configuration = new Configuration();
55 49
        $config = $this->processConfiguration($configuration, $configs);
56
57 44
        if (null === $config['view_template']) {
58 44
            $config['view_template'] = __DIR__.'/../Resources/views/health/index.html.php';
59
        }
60
61 44
        if ($config['enable_controller']) {
62 2
            $container->setParameter(sprintf('%s.view_template', $this->getAlias()), $config['view_template']);
63 2
            $container->setParameter(sprintf('%s.failure_status_code', $this->getAlias()), $config['failure_status_code']);
64 2
            $loader->load('controller.xml');
65
        }
66
67 44
        $this->configureMailer($container, $config);
68
69 44
        $container->setParameter(sprintf('%s.default_group', $this->getAlias()), $config['default_group']);
70
71
        // symfony3 does not define templating.helper.assets unless php templating is included
72 44
        if ($container->has('templating.helper.assets')) {
73
            $pathHelper = $container->getDefinition('liip_monitor.helper');
74
            $pathHelper->replaceArgument(0, 'templating.helper.assets');
75
        }
76
77
        // symfony3 does not define templating.helper.router unless php templating is included
78 44
        if ($container->has('templating.helper.router')) {
79
            $pathHelper = $container->getDefinition('liip_monitor.helper');
80
            $pathHelper->replaceArgument(1, 'templating.helper.router');
81
        }
82
83 44
        if (empty($config['checks'])) {
84 7
            return;
85
        }
86
87 37
        $checksLoaded = [];
88 37
        $containerParams = [];
89 37
        foreach ($config['checks']['groups'] as $group => $checks) {
90 37
            if (empty($checks)) {
91
                continue;
92
            }
93
94 37
            foreach ($checks as $check => $values) {
95 37
                if (empty($values)) {
96 37
                    continue;
97
                }
98
99 37
                $containerParams['groups'][$group][$check] = $values;
100 37
                $this->setParameters($container, $check, $group, $values);
101
102 37
                if (!in_array($check, $checksLoaded)) {
103 37
                    $loader->load('checks/'.$check.'.xml');
104 37
                    $checksLoaded[] = $check;
105
                }
106
            }
107
        }
108
109 37
        $container->setParameter(sprintf('%s.checks', $this->getAlias()), $containerParams);
110 37
        $this->configureDoctrineMigrationsCheck($container, $containerParams);
111 37
    }
112
113 40
    public function process(ContainerBuilder $container)
114
    {
115 40
        foreach ($this->migrationConfigurationsServices as $services) {
116
            list($configurationService, $configuration) = $services;
117
            /** @var Definition $configurationService */
118
            /** @var DoctrineMigrationConfiguration $configuration */
119
            $versions = $this->getPredefinedMigrations($container, $configuration, $this->fakeConnection);
120
            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...
121
                $configurationService->addMethodCall('registerMigrations', [$versions]);
122
            }
123
        }
124 40
    }
125
126
    /**
127
     * @param string $checkName
128
     * @param string $group
129
     * @param array  $values
130
     */
131 37
    private function setParameters(ContainerBuilder $container, $checkName, $group, $values)
132
    {
133 37
        $prefix = sprintf('%s.check.%s', $this->getAlias(), $checkName);
134 37
        switch ($checkName) {
135 37
            case 'class_exists':
136 36
            case 'cpu_performance':
137 35
            case 'php_extensions':
138 32
            case 'php_version':
139 31
            case 'php_flags':
140 30
            case 'readable_directory':
141 29
            case 'writable_directory':
142 28
            case 'process_running':
143 24
            case 'doctrine_dbal':
144 20
            case 'doctrine_mongodb':
145 20
            case 'http_service':
146 19
            case 'guzzle_http_service':
147 18
            case 'memcache':
148 17
            case 'memcached':
149 17
            case 'redis':
150 16
            case 'rabbit_mq':
151 15
            case 'stream_wrapper_exists':
152 14
            case 'file_ini':
153 13
            case 'file_json':
154 12
            case 'file_xml':
155 11
            case 'file_yaml':
156 10
            case 'expressions':
157 9
            case 'pdo_connections':
158 29
                $container->setParameter($prefix.'.'.$group, $values);
159 29
                break;
160
161 8
            case 'symfony_version':
162 7
            case 'opcache_memory':
163 2
                break;
164
165 6
            case 'doctrine_migrations':
166
                if (!class_exists(DoctrineMigrationConfiguration::class)) {
167
                    throw new \InvalidArgumentException('Please require at least "v2.0.0" of "Doctrine Migrations Library"');
168
                }
169
170
                $container->setParameter($prefix.'.'.$group, $values);
171
                break;
172
        }
173
174 37
        if (is_array($values)) {
175 33
            foreach ($values as $key => $value) {
176 33
                $container->setParameter($prefix.'.'.$key.'.'.$group, $value);
177
            }
178
        }
179 37
    }
180
181
    /**
182
     * Set up doctrine migration configuration services.
183
     *
184
     * @param ContainerBuilder $container The container
185
     * @param array            $params    Container params
186
     *
187
     * @return void
188
     */
189 37
    private function configureDoctrineMigrationsCheck(ContainerBuilder $container, array $params)
190
    {
191 37
        if (!$container->hasDefinition('liip_monitor.check.doctrine_migrations') || !isset($params['groups'])) {
192 37
            return;
193
        }
194
195
        foreach ($params['groups'] as $groupName => $groupChecks) {
196
            if (!isset($groupChecks['doctrine_migrations'])) {
197
                continue;
198
            }
199
200
            $services = [];
201
            foreach ($groupChecks['doctrine_migrations'] as $key => $config) {
202
                try {
203
                    $serviceConfiguration =
204
                        $this->createMigrationConfigurationService($container, $config['connection'], $config['configuration_file'] ?? null);
205
206
                    $serviceId = sprintf('liip_monitor.check.doctrine_migrations.configuration.%s.%s', $groupName, $key);
207
                    $container->setDefinition($serviceId, $serviceConfiguration);
208
209
                    $services[$key] = $serviceId;
210
                } catch (MigrationException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\Migrations\MigrationException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
211
                    throw new MigrationException(sprintf('Invalid doctrine migration check under "%s.%s": %s', $groupName, $key, $e->getMessage()), $e->getCode(), $e);
212
                }
213
            }
214
215
            $parameter = sprintf('%s.check.%s.%s', $this->getAlias(), 'doctrine_migrations', $groupName);
216
            $container->setParameter($parameter, $services);
217
        }
218
    }
219
220 44
    private function configureMailer(ContainerBuilder $container, array $config)
221
    {
222 44
        if (false === $config['mailer']['enabled']) {
223 43
            return;
224
        }
225
226 1
        foreach ($config['mailer'] as $key => $value) {
227 1
            $container->setParameter(sprintf('%s.mailer.%s', $this->getAlias(), $key), $value);
228
        }
229 1
    }
230
231
    /**
232
     * Return key-value array with migration version as key and class as a value defined in config file.
233
     *
234
     * @param ContainerBuilder               $container  The container
235
     * @param DoctrineMigrationConfiguration $config     Current configuration
236
     * @param Connection                     $connection Fake connections
237
     *
238
     * @return array[]
239
     */
240
    private function getPredefinedMigrations(ContainerBuilder $container, DoctrineMigrationConfiguration $config, Connection $connection)
241
    {
242
        $result = [];
243
244
        $diff = new LiipMigrationConfiguration($connection);
245
246
        if ($namespace = $config->getMigrationsNamespace()) {
0 ignored issues
show
Unused Code introduced by
$namespace is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
247
            $diff->setMigrationsNamespace($config->getMigrationsNamespace());
248
        }
249
250
        if ($dir = $config->getMigrationsDirectory()) {
251
            $diff->setMigrationsDirectory($dir);
252
        }
253
254
        $diff->setContainer($container);
255
        $diff->configure();
256
257
        foreach ($config->getMigrations() as $version) {
258
            $result[$version->getVersion()] = get_class($version->getMigration());
259
        }
260
261
        foreach ($diff->getAvailableVersions() as $version) {
262
            unset($result[$version]);
263
        }
264
265
        return $result;
266
    }
267
268
    /**
269
     * Creates migration configuration service definition.
270
     *
271
     * @param ContainerBuilder $container      DI Container
272
     * @param string           $connectionName Connection name for container service
273
     * @param string           $filename       File name with migration configuration
274
     *
275
     * @return DefinitionDecorator|ChildDefinition
276
     */
277
    private function createMigrationConfigurationService(ContainerBuilder $container, string $connectionName, string $filename = null)
278
    {
279
        $configuration = $this->createTemporaryConfiguration($container, $this->fakeConnection, $filename);
280
281
        $configurationServiceName = 'liip_monitor.check.doctrine_migrations.abstract_configuration';
282
        $serviceConfiguration = class_exists('Symfony\Component\DependencyInjection\ChildDefinition')
283
            ? new ChildDefinition($configurationServiceName)
284
            : new DefinitionDecorator($configurationServiceName)
285
        ;
286
287
        $this->migrationConfigurationsServices[] = [$serviceConfiguration, $configuration];
288
289
        $serviceConfiguration->replaceArgument(
290
            0,
291
            new Reference(sprintf('doctrine.dbal.%s_connection', $connectionName))
292
        );
293
294
        if ($configuration->getMigrationsNamespace()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $configuration->getMigrationsNamespace() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
295
            $serviceConfiguration->addMethodCall(
296
                'setMigrationsNamespace',
297
                [$configuration->getMigrationsNamespace()]
298
            );
299
        }
300
301
        if ($configuration->getMigrationsTableName()) {
302
            $serviceConfiguration->addMethodCall(
303
                'setMigrationsTableName',
304
                [$configuration->getMigrationsTableName()]
305
            );
306
        }
307
308
        if ($configuration->getMigrationsColumnName()) {
309
            $serviceConfiguration->addMethodCall(
310
                'setMigrationsColumnName',
311
                [$configuration->getMigrationsColumnName()]
312
            );
313
        }
314
315
        if ($configuration->getName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $configuration->getName() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
316
            $serviceConfiguration->addMethodCall('setName', [$configuration->getName()]);
317
        }
318
319
        if ($configuration->getMigrationsDirectory()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $configuration->getMigrationsDirectory() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
320
            $directory = $configuration->getMigrationsDirectory();
321
            $pathPlaceholders = ['kernel.root_dir', 'kernel.cache_dir', 'kernel.logs_dir'];
322
            foreach ($pathPlaceholders as $parameter) {
323
                $kernelDir = realpath($container->getParameter($parameter));
324
                if (0 === strpos(realpath($directory), $kernelDir)) {
325
                    $directory = str_replace($kernelDir, "%{$parameter}%", $directory);
326
                    break;
327
                }
328
            }
329
330
            $serviceConfiguration->addMethodCall(
331
                'setMigrationsDirectory',
332
                [$directory]
333
            );
334
        }
335
336
        $serviceConfiguration->addMethodCall('configure', []);
337
338
        if ($configuration->areMigrationsOrganizedByYear()) {
339
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYear', [true]);
340
341
            return $serviceConfiguration;
342
        } elseif ($configuration->areMigrationsOrganizedByYearAndMonth()) {
343
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYearAndMonth', [true]);
344
345
            return $serviceConfiguration;
346
        }
347
348
        return $serviceConfiguration;
349
    }
350
351
    /**
352
     * Creates in-memory migration configuration for setting up container service.
353
     *
354
     * @param ContainerBuilder $container  The container
355
     * @param Connection       $connection Fake connection
356
     * @param string           $filename   Migrations configuration file
357
     */
358
    private function createTemporaryConfiguration(
359
        ContainerBuilder $container,
360
        Connection $connection,
361
        string $filename = null
362
    ): DoctrineMigrationConfiguration {
363
        if (null === $filename) {
364
            // this is configured from migrations bundle
365
            return new DoctrineMigrationConfiguration($connection);
366
        }
367
368
        // -------
369
        // This part must be in sync with Doctrine\Migrations\Tools\Console\Helper\ConfigurationHelper::loadConfig
370
        $map = [
371
            'xml' => '\XmlConfiguration',
372
            'yaml' => '\YamlConfiguration',
373
            'yml' => '\YamlConfiguration',
374
            'php' => '\ArrayConfiguration',
375
            'json' => '\JsonConfiguration',
376
        ];
377
        // --------
378
379
        $filename = $container->getParameterBag()->resolveValue($filename);
380
        $info = pathinfo($filename);
381
        // check we can support this file type
382
        if (empty($map[$info['extension']])) {
383
            throw new \InvalidArgumentException('Given config file type is not supported');
384
        }
385
386
        $class = 'Doctrine\Migrations\Configuration';
387
        $class .= $map[$info['extension']];
388
        // -------
389
390
        /** @var AbstractFileConfiguration $configuration */
391
        $configuration = new $class($connection);
392
        $configuration->load($filename);
393
        $configuration->validate();
394
395
        return $configuration;
396
    }
397
}
398