Completed
Pull Request — master (#165)
by Lukas Kahwe
02:13 queued 49s
created

createTemporaryConfiguration()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 17
nc 2
nop 3
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\Exception\LogicException;
13
use Symfony\Component\DependencyInjection\Loader;
14
use Symfony\Component\DependencyInjection\Reference;
15
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
16
17
class LiipMonitorExtension extends Extension
18
{
19
    /**
20
     * Loads the services based on your application configuration.
21
     *
22
     * @param array            $configs
23
     * @param ContainerBuilder $container
24
     */
25
    public function load(array $configs, ContainerBuilder $container)
26
    {
27
        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
28
        $loader->load('runner.xml');
29
        $loader->load('helper.xml');
30
31
        $configuration = new Configuration();
32
        $config = $this->processConfiguration($configuration, $configs);
33
34
        if (null === $config['view_template']) {
35
            $config['view_template'] = __DIR__.'/../Resources/views/health/index.html.php';
36
        }
37
38
        if ($config['enable_controller']) {
39
            if (!$container->has('assets.packages')) {
40
                throw new LogicException('Controller support cannot be enabled unless the frameworkbundle "assets" support is also enabled.');
41
            }
42
            $container->setParameter(sprintf('%s.view_template', $this->getAlias()), $config['view_template']);
43
            $loader->load('controller.xml');
44
        }
45
46
        if ($config['mailer']['enabled']) {
47
            $loader->load('helper/swift_mailer.xml');
48
49
            foreach ($config['mailer'] as $key => $value) {
50
                $container->setParameter(sprintf('%s.mailer.%s', $this->getAlias(), $key), $value);
51
            }
52
        }
53
54
        $container->setParameter(sprintf('%s.default_group', $this->getAlias()), $config['default_group']);
55
56
        // symfony3 does not define templating.helper.assets unless php templating is included
57
        if ($container->has('templating.helper.assets')) {
58
            $pathHelper = $container->getDefinition('liip_monitor.helper');
59
            $pathHelper->replaceArgument(0, 'templating.helper.assets');
60
        }
61
62
        // symfony3 does not define templating.helper.router unless php templating is included
63
        if ($container->has('templating.helper.router')) {
64
            $pathHelper = $container->getDefinition('liip_monitor.helper');
65
            $pathHelper->replaceArgument(1, 'templating.helper.router');
66
        }
67
68
        if (empty($config['checks'])) {
69
            return;
70
        }
71
72
        $checksLoaded = array();
73
        $containerParams = array();
74
        foreach ($config['checks']['groups'] as $group => $checks) {
75
            if (empty($checks)) {
76
                continue;
77
            }
78
79
            foreach ($checks as $check => $values) {
80
                if (empty($values)) {
81
                    continue;
82
                }
83
84
                $containerParams['groups'][$group][$check] = $values;
85
                $this->setParameters($container, $check, $group, $values);
86
87
                if (!in_array($check, $checksLoaded)) {
88
                    $loader->load('checks/'.$check.'.xml');
89
                    $checksLoaded[] = $check;
90
                }
91
            }
92
        }
93
94
        $container->setParameter(sprintf('%s.checks', $this->getAlias()), $containerParams);
95
        $this->configureDoctrineMigrationsCheck($container, $containerParams);
96
    }
97
98
    /**
99
     * @param ContainerBuilder $container
100
     * @param string           $checkName
101
     * @param string           $group
102
     * @param array            $values
103
     */
104
    private function setParameters(ContainerBuilder $container, $checkName, $group, $values)
105
    {
106
        $prefix = sprintf('%s.check.%s', $this->getAlias(), $checkName);
107
        switch ($checkName) {
108
            case 'class_exists':
109
            case 'cpu_performance':
110
            case 'php_extensions':
111
            case 'php_version':
112
            case 'php_flags':
113
            case 'readable_directory':
114
            case 'writable_directory':
115
            case 'process_running':
116
            case 'doctrine_dbal':
117
            case 'doctrine_mongodb':
118
            case 'http_service':
119
            case 'guzzle_http_service':
120
            case 'memcache':
121
            case 'redis':
122
            case 'rabbit_mq':
123
            case 'stream_wrapper_exists':
124
            case 'file_ini':
125
            case 'file_json':
126
            case 'file_xml':
127
            case 'file_yaml':
128
            case 'expressions':
129
                $container->setParameter($prefix.'.'.$group, $values);
130
                continue;
131
132
            case 'symfony_version':
133
                continue;
134
135
            case 'opcache_memory':
136
                if (!class_exists('ZendDiagnostics\Check\OpCacheMemory')) {
137
                    throw new \InvalidArgumentException('Please require at least "v1.0.4" of "ZendDiagnostics"');
138
                }
139
                continue;
140
141
            case 'doctrine_migrations':
142
                if (!class_exists('ZendDiagnostics\Check\DoctrineMigration')) {
143
                    throw new \InvalidArgumentException('Please require at least "v1.0.6" of "ZendDiagnostics"');
144
                }
145
146
                if (!class_exists('Doctrine\Bundle\MigrationsBundle\Command\DoctrineCommand')) {
147
                    throw new \InvalidArgumentException('Please require at least "v1.0.0" of "DoctrineMigrationsBundle"');
148
                }
149
150
                if (!class_exists('Doctrine\DBAL\Migrations\Configuration\Configuration')) {
151
                    throw new \InvalidArgumentException('Please require at least "v1.1.0" of "Doctrine Migrations Library"');
152
                }
153
154
                $container->setParameter($prefix.'.'.$group, $values);
155
                continue;
156
157
            case 'pdo_connections':
158
                if (!class_exists('ZendDiagnostics\Check\PDOCheck')) {
159
                    throw new \InvalidArgumentException('Please require at least "v1.0.5" of "ZendDiagnostics"');
160
                }
161
                $container->setParameter($prefix.'.'.$group, $values);
162
                continue;
163
164
        }
165
166
        if (is_array($values)) {
167
            foreach ($values as $key => $value) {
168
                $container->setParameter($prefix.'.'.$key.'.'.$group, $value);
169
            }
170
        }
171
    }
172
173
    /**
174
     * Set up doctrine migration configuration services
175
     *
176
     * @param ContainerBuilder $container The container
177
     * @param array            $params    Container params
178
     *
179
     * @return void
180
     */
181
    private function configureDoctrineMigrationsCheck(ContainerBuilder $container, array $params)
182
    {
183
        if (!$container->hasDefinition('liip_monitor.check.doctrine_migrations') || !isset($params['groups'])) {
184
            return;
185
        }
186
187
        foreach ($params['groups'] as $groupName => $groupChecks) {
188
            if (!isset($groupChecks['doctrine_migrations'])) {
189
                continue;
190
            }
191
192
            $services = [];
193
            foreach ($groupChecks['doctrine_migrations'] as $key => $config) {
194
                $serviceConfiguration =
195
                    $this->createMigrationConfigurationService($container, $config['configuration_file'], $config[ 'connection' ]);
196
197
                $serviceId = sprintf('liip_monitor.check.doctrine_migrations.configuration.%s.%s', $groupName, $key);
198
                $container->setDefinition($serviceId, $serviceConfiguration);
199
200
                $services[$key] = $serviceId;
201
            }
202
203
            $parameter = sprintf('%s.check.%s.%s', $this->getAlias(), 'doctrine_migrations', $groupName);
204
            $container->setParameter($parameter, $services);
205
        }
206
    }
207
208
    /**
209
     * Return key-value array with migration version as key and class as a value defined in config file
210
     *
211
     * @param AbstractFileConfiguration $config Current configuration
212
     * @param Connection                $connection Fake connections
213
     *
214
     * @return array[]
215
     */
216
    private function getPredefinedMigrations(AbstractFileConfiguration $config, Connection $connection)
217
    {
218
        $result = array();
219
220
        $diff = new MigrationConfiguration($connection);
221
        $diff->setMigrationsNamespace($config->getMigrationsNamespace());
222
        $diff->setMigrationsDirectory($config->getMigrationsDirectory());
223
        foreach ($config->getMigrations() as $version) {
224
            $result[$version->getVersion()] = get_class($version->getMigration());
225
        }
226
227
        foreach ($diff->getAvailableVersions() as $version) {
228
            unset($result[$version]);
229
        }
230
231
        return $result;
232
    }
233
234
    /**
235
     * Creates migration configuration service definition
236
     *
237
     * @param ContainerBuilder $container      DI Container
238
     * @param string           $filename       File name with migration configuration
239
     * @param string           $connectionName Connection name for container service
240
     *
241
     * @return DefinitionDecorator
242
     */
243
    private function createMigrationConfigurationService(ContainerBuilder $container, $filename, $connectionName)
244
    {
245
        /** @var AbstractFileConfiguration $configuration */
246
        $connection    = new Connection([], new Driver()); // needed for correct migration loading
247
        $configuration = $this->createTemporaryConfiguration($container, $connection, $filename);
248
249
        $serviceConfiguration =
250
            new DefinitionDecorator('liip_monitor.check.doctrine_migrations.abstract_configuration');
251
        $serviceConfiguration->replaceArgument(
252
            0,
253
            new Reference(sprintf('doctrine.dbal.%s_connection', $connectionName))
254
        );
255
256
        if ($configuration->getMigrationsNamespace()) {
257
            $serviceConfiguration->addMethodCall(
258
                'setMigrationsNamespace',
259
                [ $configuration->getMigrationsNamespace() ]
260
            );
261
        }
262
263
        if ($configuration->getMigrationsTableName()) {
264
            $serviceConfiguration->addMethodCall(
265
                'setMigrationsTableName',
266
                [ $configuration->getMigrationsTableName() ]
267
            );
268
        }
269
270
        if ($configuration->getMigrationsColumnName()) {
271
            $serviceConfiguration->addMethodCall(
272
                'setMigrationsColumnName',
273
                [ $configuration->getMigrationsColumnName() ]
274
            );
275
        }
276
277
        if ($configuration->getName()) {
278
            $serviceConfiguration->addMethodCall('setName', [ $configuration->getName() ]);
279
        }
280
281
        if ($configuration->getMigrationsDirectory()) {
282
            $directory        = $configuration->getMigrationsDirectory();
283
            $pathPlaceholders = array('kernel.root_dir', 'kernel.cache_dir', 'kernel.logs_dir');
284
            foreach ($pathPlaceholders as $parameter) {
285
                $kernelDir = realpath($container->getParameter($parameter));
286
                if (strpos(realpath($directory), $kernelDir) === 0) {
287
                    $directory = str_replace($kernelDir, "%{$parameter}%", $directory);
288
                    break;
289
                }
290
            }
291
292
293
            $serviceConfiguration->addMethodCall(
294
                'setMigrationsDirectory',
295
                [ $directory ]
296
            );
297
        }
298
299
        /** @var AbstractFileConfiguration $diff */
300
        $versions = $this->getPredefinedMigrations($configuration, $connection);
301
        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...
302
            $serviceConfiguration->addMethodCall('registerMigrations', [ $versions ]);
303
        }
304
305
        $serviceConfiguration->addMethodCall('configure', []);
306
307
        if ($configuration->areMigrationsOrganizedByYear()) {
308
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYear', [ true ]);
309
310
            return $serviceConfiguration;
311
        } elseif ($configuration->areMigrationsOrganizedByYearAndMonth()) {
312
            $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYearAndMonth', [ true ]);
313
314
            return $serviceConfiguration;
315
        }
316
317
        return $serviceConfiguration;
318
    }
319
320
    /**
321
     * Creates in-memory migration configuration for setting up container service
322
     *
323
     * @param ContainerBuilder $container  The container
324
     * @param Connection       $connection Fake connection
325
     * @param string           $filename   Migrations configuration file
326
     *
327
     * @return AbstractFileConfiguration
328
     */
329
    private function createTemporaryConfiguration(ContainerBuilder $container, Connection $connection, $filename)
330
    {
331
        // -------
332
        // This part must be in sync with Doctrine\DBAL\Migrations\Tools\Console\Helper\ConfigurationHelper::loadConfig
333
        $map = [
334
            'xml'  => '\XmlConfiguration',
335
            'yaml' => '\YamlConfiguration',
336
            'yml'  => '\YamlConfiguration',
337
            'php'  => '\ArrayConfiguration',
338
            'json' => '\JsonConfiguration',
339
        ];
340
        // --------
341
342
        $filename = $container->getParameterBag()->resolveValue($filename);
343
        $info     = pathinfo($filename);
344
        // check we can support this file type
345
        if (empty($map[ $info[ 'extension' ] ])) {
346
            throw new \InvalidArgumentException('Given config file type is not supported');
347
        }
348
349
        $class = 'Doctrine\DBAL\Migrations\Configuration';
350
        $class .= $map[ $info[ 'extension' ] ];
351
        // -------
352
353
        /** @var AbstractFileConfiguration $configuration */
354
        $configuration = new $class($connection);
355
        $configuration->load($filename);
356
        $configuration->validate();
357
358
        return $configuration;
359
    }
360
}
361