Completed
Push — master ( 52b242...112fdc )
by Thomas
17s queued 11s
created

ConfigurationManager::setActionsConfigurations()   B

Complexity

Conditions 10
Paths 18

Size

Total Lines 74
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 14.5537

Importance

Changes 0
Metric Value
cc 10
eloc 47
c 0
b 0
f 0
nc 18
nop 2
dl 0
loc 74
ccs 18
cts 28
cp 0.6429
crap 14.5537
rs 7.2896

How to fix   Long Method    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
declare(strict_types=1);
4
5
/*
6
 * This file is part of the ekino Drupal Debug project.
7
 *
8
 * (c) ekino
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Ekino\Drupal\Debug\Configuration;
15
16
use Ekino\Drupal\Debug\ActionMetadata\ActionMetadataFactory;
17
use Ekino\Drupal\Debug\ActionMetadata\ActionMetadataManager;
18
use Ekino\Drupal\Debug\Cache\FileCache;
19
use Ekino\Drupal\Debug\Configuration\Model\ActionConfiguration;
20
use Ekino\Drupal\Debug\Configuration\Model\DefaultsConfiguration as DefaultsConfigurationModel;
21
use Ekino\Drupal\Debug\Configuration\Model\SubstituteOriginalDrupalKernelConfiguration as SubstituteOriginalDrupalKernelConfigurationModel;
22
use Ekino\Drupal\Debug\Resource\Model\ResourcesCollection;
23
use Symfony\Component\Config\Definition\ConfigurationInterface;
24
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
25
use Symfony\Component\Config\Definition\Processor;
26
use Symfony\Component\Config\Resource\FileExistenceResource;
27
use Symfony\Component\Config\Resource\FileResource;
28
use Symfony\Component\Filesystem\Filesystem;
29
use Symfony\Component\PropertyAccess\PropertyAccess;
30
use Symfony\Component\PropertyAccess\PropertyAccessor;
31
use Symfony\Component\Yaml\Parser;
32
33
class ConfigurationManager
34
{
35
    /**
36
     * @var string
37
     */
38
    public const CONFIGURATION_FILE_PATH_ENVIRONMENT_VARIABLE_NAME = 'DRUPAL_DEBUG_CONFIGURATION_FILE_PATH';
39
40
    /**
41
     * @var string
42
     */
43
    public const CONFIGURATION_CACHE_DIRECTORY_ENVIRONMENT_VARIABLE_NAME = 'DRUPAL_DEBUG_CONFIGURATION_CACHE_DIRECTORY_PATH';
44
45
    /**
46
     * @var string
47
     */
48
    public const ROOT_KEY = 'drupal-debug';
49
50
    /**
51
     * @var string
52
     */
53
    private const DEFAULT_CONFIGURATION_FILE_NAME = 'drupal-debug.yml.dist';
54
55
    /**
56
     * @var self|null
57
     */
58
    private static $instance = null;
59
60
    /**
61
     * @var Filesystem
62
     */
63
    private $filesystem;
64
65
    /**
66
     * @var PropertyAccessor
67
     */
68
    private $propertyAccessor;
69
70
    /**
71
     * @var bool
72
     */
73
    private $configurationChanged;
74
75
    /**
76
     * @var string
77
     */
78
    private $configurationFilePath;
79
80
    /**
81
     * @var bool
82
     */
83
    private $configurationFilePathExists;
84
85
    /**
86
     * @var string
87
     */
88
    private $configurationFilePathDirectory;
89
90
    /**
91
     * @var DefaultsConfigurationModel
92
     */
93
    private $defaultsConfiguration;
94
95
    /**
96
     * @var SubstituteOriginalDrupalKernelConfigurationModel
97
     */
98
    private $substituteOriginalDrupalKernelConfiguration;
99
100
    /**
101
     * @var ActionConfiguration[]
102
     */
103
    private $actionsConfigurations;
104
105 35
    private function __construct()
106
    {
107 35
        $configurationCacheDirectory = \getenv(self::CONFIGURATION_CACHE_DIRECTORY_ENVIRONMENT_VARIABLE_NAME);
108 35
        if (false === $configurationCacheDirectory) {
109 33
            $configurationCacheDirectory = \sys_get_temp_dir();
110
        }
111
112 35
        $this->filesystem = new Filesystem();
113
114 35
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
115
116 35
        $this->setConfigurationFilePathInfo();
117
118 35
        $fileCache = new FileCache(\sprintf('%s/drupal_debug_configuration.php', $configurationCacheDirectory), new ResourcesCollection(array(
119 35
            $this->doesConfigurationFilePathExists() ? new FileResource($this->configurationFilePath) : new FileExistenceResource($this->configurationFilePath),
120 35
            new FileResource(\sprintf('%s/ConfigurationManager.php', __DIR__)),
121
        )));
122
123 35
        if (!($this->configurationChanged = !$fileCache->isFresh() || empty($data = $fileCache->getData()))) {
124
            list(
125 16
                'defaults' => $this->defaultsConfiguration,
126 16
                'substitute_original_drupal_kernel' => $this->substituteOriginalDrupalKernelConfiguration,
127
                'actions' => $this->actionsConfigurations) = \array_map(static function ($serializedConfiguration) {
128 16
                    return \unserialize($serializedConfiguration);
129 16
                }, $data ?? $fileCache->getData());
130
        } else {
131 19
            $configurationFileContent = $this->getConfigurationFileContent();
132
133 19
            $this->setDefaultsConfiguration($configurationFileContent[self::ROOT_KEY][DefaultsConfiguration::ROOT_KEY] ?? array());
134 19
            $this->setSubstituteOriginalDrupalKernelConfiguration($configurationFileContent[self::ROOT_KEY][SubstituteOriginalDrupalKernelConfiguration::ROOT_KEY] ?? array(), $defaultsConfiguration = $this->getDefaultsConfiguration());
135 19
            $this->setActionsConfigurations($configurationFileContent[self::ROOT_KEY][ActionsConfiguration::ROOT_KEY] ?? array(), $defaultsConfiguration);
136
137 19
            $fileCache->invalidate();
138 19
            $fileCache->write(array(
139 19
                'defaults' => \serialize($this->defaultsConfiguration),
140 19
                'substitute_original_drupal_kernel' => \serialize($this->substituteOriginalDrupalKernelConfiguration),
141 19
                'actions' => \serialize($this->actionsConfigurations),
142
            ));
143
        }
144 35
    }
145
146 35
    public static function getInstance(): self
147
    {
148 35
        if (!self::$instance instanceof self) {
149 35
            self::$instance = new self();
150
        }
151
152 35
        return self::$instance;
153
    }
154
155 19
    public function getDefaultsConfiguration(): DefaultsConfigurationModel
156
    {
157 19
        return $this->defaultsConfiguration;
158
    }
159
160 19
    private function setDefaultsConfiguration($configurationFileContent): void
161
    {
162 19
        $this->defaultsConfiguration = new DefaultsConfigurationModel(
163 19
            $this->makeRelativePathsAbsolutes(
164 19
                $this->getProcessedDefaultsConfiguration($configurationFileContent),
165
                \array_map(static function (array $elements): string {
166 19
                    return \sprintf('[%s]', \implode('][', $elements));
167 19
                }, array(
168
                    array(
169 19
                        'cache_directory_path',
170
                    ),
171
                    array(
172
                        'logger',
173
                        'file_path',
174
                    ),
175
                ))
176
            )
177
        );
178 19
    }
179
180
    public function getSubstituteOriginalDrupalKernelConfiguration(): SubstituteOriginalDrupalKernelConfigurationModel
181
    {
182
        return $this->substituteOriginalDrupalKernelConfiguration;
183
    }
184
185 19
    private function setSubstituteOriginalDrupalKernelConfiguration($configurationFileContent, DefaultsConfigurationModel $defaultsConfiguration): void
186
    {
187 19
        $this->substituteOriginalDrupalKernelConfiguration = new SubstituteOriginalDrupalKernelConfigurationModel(
188 19
            $this->makeRelativePathsAbsolutes(
189 19
                $this->getProcessedSubstituteOriginalDrupalKernelConfiguration($configurationFileContent, $defaultsConfiguration),
190
                \array_map(static function (array $elements): string {
191 19
                    return \sprintf('[%s]', \implode('][', $elements));
192 19
                }, array(
193
                    array(
194 19
                        'composer_autoload_file_path',
195
                    ),
196
                    array(
197
                        'cache_directory_path',
198
                    ),
199
                ))
200
            )
201
        );
202 19
    }
203
204 2
    public function getActionConfiguration(string $class): ActionConfiguration
205
    {
206 2
        return $this->actionsConfigurations[$class];
207
    }
208
209 19
    private function setActionsConfigurations($configurationFileContent, DefaultsConfigurationModel $defaultsConfiguration): void
210
    {
211 19
        $this->actionsConfigurations = array();
212
213 19
        $actionMetadataManager = ActionMetadataManager::getInstance();
214 19
        $actionMetadataFactory = new ActionMetadataFactory();
215
216 19
        foreach ($configurationFileContent as $shortName => $config) {
217 4
            if ($actionMetadataManager->isCoreAction($shortName)) {
218 4
                continue;
219
            }
220
221
            $actionMetadataManager->add($actionMetadataFactory->create($shortName));
222
        }
223
224 19
        $processedActionsConfiguration = $this->getProcessedActionsConfiguration($configurationFileContent, $actionMetadataManager->all(), $defaultsConfiguration);
225
        $propertyPaths = \array_map(static function (array $elements): string {
226 19
            return \sprintf('[%s]', \implode('][', $elements));
227 19
        }, array(
228
            array(
229 19
                'display_pretty_exceptions',
230
                'logger',
231
                'file_path',
232
            ),
233
            array(
234
                'throw_errors_as_exceptions',
235
                'logger',
236
                'file_path',
237
            ),
238
            array(
239
                'watch_container_definitions',
240
                'cache_directory_path',
241
            ),
242
            array(
243
                'watch_modules_hooks_implementations',
244
                'cache_directory_path',
245
            ),
246
            array(
247
                'watch_routing_definitions',
248
                'cache_directory_path',
249
            ),
250
        ));
251
252
        $buildPropertyPathsRecursively = static function (array $array, array $previous) use (&$buildPropertyPathsRecursively, &$propertyPaths): void {
253
            foreach ($array as $key => $row) {
254
                if (\is_string($row) && 1 === \preg_match('/_path$/i', $key)) {
255
                    $propertyPaths[] = \sprintf('[%s]', \implode('][', \array_merge($previous, array(
256
                        $key,
257
                    ))));
258
                } elseif (\is_array($row)) {
259
                    $buildPropertyPathsRecursively($row, \array_merge($previous, array(
260
                        $key,
261
                    )));
262
                }
263
            }
264 19
        };
265
266 19
        foreach ($processedActionsConfiguration as $shortName => $processedActionConfiguration) {
267 19
            if ($actionMetadataManager->isCoreAction($shortName)) {
268 19
                continue;
269
            }
270
271
            $buildPropertyPathsRecursively($processedActionConfiguration, array(
272
                $shortName,
273
            ));
274
        }
275
276
        foreach (
277 19
            $this->makeRelativePathsAbsolutes(
278 19
                $processedActionsConfiguration,
279
                $propertyPaths
280
            ) as $shortName => $processedActionConfiguration
281
        ) {
282 19
            $this->actionsConfigurations[$shortName] = new ActionConfiguration($processedActionConfiguration);
283
        }
284 19
    }
285
286 18
    public function getConfigurationFilePath(): string
287
    {
288 18
        return $this->configurationFilePath;
289
    }
290
291 35
    public function doesConfigurationFilePathExists(): bool
292
    {
293 35
        return $this->configurationFilePathExists;
294
    }
295
296 6
    public function doesConfigurationChanged(): bool
297
    {
298 6
        return $this->configurationChanged;
299
    }
300
301 35
    private function setConfigurationFilePathInfo(): void
302
    {
303 35
        $possibleConfigurationFilePath = \getenv(self::CONFIGURATION_FILE_PATH_ENVIRONMENT_VARIABLE_NAME);
304 35
        if (false === $possibleConfigurationFilePath) {
305
            // The default configuration file location is the same than the vendor directory.
306
            $possibleAutoloadPaths = array(
307
                // Vendor of a project : Configuration\src\drupal-debug\ekino\autoload.php
308 13
                \sprintf('%s/../../../../autoload.php', __DIR__),
309
                // Directly this project : Configuration\src\/vendor/autoload.php
310 13
                \sprintf('%s/../../vendor/autoload.php', __DIR__),
311
                // For other cases (if they exist), please use the dedicated environment variable.
312
            );
313
314 13
            foreach ($possibleAutoloadPaths as $possibleAutoloadPath) {
315 13
                if (\is_file($possibleAutoloadPath)) {
316 13
                    $possibleConfigurationFilePath = \sprintf('%s/../%s', \dirname($possibleAutoloadPath), self::DEFAULT_CONFIGURATION_FILE_NAME);
317
318 13
                    break;
319
                }
320
            }
321
322 13
            if (false === $possibleConfigurationFilePath) {
323
                throw new \RuntimeException('The composer autoload.php file could not be found.');
324
            }
325
        }
326
327 35
        $possibleConfigurationFilePaths = \array_unique(array(
328 35
            $possibleConfigurationFilePath,
329 35
            \rtrim($possibleConfigurationFilePath, '.dist'),
330
        ));
331
332 35
        $exists = false;
333 35
        foreach ($possibleConfigurationFilePaths as $possibleConfigurationFilePath) {
334 35
            if (\is_file($possibleConfigurationFilePath)) {
335 14
                $exists = true;
336
337 14
                break;
338
            }
339
        }
340
341 35
        $this->configurationFilePath = $possibleConfigurationFilePath;
342 35
        $this->configurationFilePathExists = $exists;
343 35
        $this->configurationFilePathDirectory = \dirname($this->configurationFilePath);
344 35
    }
345
346 19
    private function getConfigurationFileContent(): array
347
    {
348 19
        if (!$this->configurationFilePathExists) {
349 7
            return array();
350
        }
351
352 12
        $parser = new Parser();
353 12
        $content = $parser->parseFile($this->configurationFilePath);
354 12
        if (!\is_array($content)) {
355
            throw new InvalidConfigurationException('The content of the drupal-debug configuration file should be an array.');
356
        }
357
358 12
        return $content;
359
    }
360
361
    /**
362
     * @internal
363
     */
364 19
    public function getProcessedDefaultsConfiguration($configurationFileContent): array
365
    {
366 19
        return $this->getProcessedConfiguration(
367
            array(
368 19
                DefaultsConfiguration::ROOT_KEY => $configurationFileContent,
369
            ),
370 19
            new DefaultsConfiguration()
371
        );
372
    }
373
374 19
    private function getProcessedSubstituteOriginalDrupalKernelConfiguration($configurationFileContent, DefaultsConfigurationModel $defaultsConfiguration): array
375
    {
376 19
        return $this->getProcessedConfiguration(
377
            array(
378 19
                SubstituteOriginalDrupalKernelConfiguration::ROOT_KEY => $configurationFileContent,
379
            ),
380 19
            new SubstituteOriginalDrupalKernelConfiguration($defaultsConfiguration)
381
        );
382
    }
383
384 19
    private function getProcessedActionsConfiguration($configurationFileContent, array $actionMetadata, DefaultsConfigurationModel $defaultsConfiguration): array
385
    {
386 19
        return $this->getProcessedConfiguration(
387
            array(
388 19
                ActionsConfiguration::ROOT_KEY => $configurationFileContent,
389
            ),
390 19
            new ActionsConfiguration($actionMetadata, $defaultsConfiguration)
391
        );
392
    }
393
394 19
    private function getProcessedConfiguration(array $configurationFileContent, ConfigurationInterface $configuration): array
395
    {
396 19
        return (new Processor())->process(
397 19
            $configuration
398 19
                ->getConfigTreeBuilder()
399 19
                ->buildTree(),
400
            $configurationFileContent
401
        );
402
    }
403
404 19
    private function makeRelativePathsAbsolutes(array $processedConfiguration, array $propertyPaths): array
405
    {
406 19
        foreach ($propertyPaths as $propertyPath) {
407 19
            if (!$this->propertyAccessor->isReadable($processedConfiguration, $propertyPath)) {
408
                continue;
409
            }
410
411 19
            $path = $this->propertyAccessor->getValue($processedConfiguration, $propertyPath);
412 19
            if (null === $path || '' === $path) {
413
                continue;
414
            }
415
416 19
            if (!$this->filesystem->isAbsolutePath($path)) {
417 19
                $this->propertyAccessor->setValue($processedConfiguration, $propertyPath, \sprintf('%s/%s', $this->configurationFilePathDirectory, $path));
418
            }
419
        }
420
421 19
        return $processedConfiguration;
422
    }
423
}
424