Completed
Push — master ( ef5d35...9af83e )
by Thomas
12s queued 10s
created

getConfigurationFileContent()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 0
dl 0
loc 14
ccs 0
cts 9
cp 0
crap 12
rs 10
c 0
b 0
f 0
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\Cache\FileCache;
17
use Ekino\Drupal\Debug\Configuration\Model\DefaultsConfiguration;
18
use Ekino\Drupal\Debug\Configuration\Model\SubstituteOriginalDrupalKernelConfiguration;
19
use Ekino\Drupal\Debug\Resource\Model\ResourcesCollection;
20
use Symfony\Component\Config\Definition\Processor;
21
use Symfony\Component\Config\Resource\FileExistenceResource;
22
use Symfony\Component\Config\Resource\FileResource;
23
use Symfony\Component\Filesystem\Filesystem;
24
use Symfony\Component\PropertyAccess\PropertyAccess;
25
use Symfony\Component\Yaml\Parser;
26
27
class ConfigurationManager
28
{
29
    /**
30
     * @var string
31
     */
32
    const CONFIGURATION_FILE_PATH_ENVIRONMENT_VARIABLE_NAME = 'DRUPAL_DEBUG_CONFIGURATION_FILE_PATH';
33
34
    /**
35
     * @var string
36
     */
37
    const CONFIGURATION_CACHE_DIRECTORY_ENVIRONMENT_VARIABLE_NAME = 'DRUPAL_DEBUG_CONFIGURATION_CACHE_DIRECTORY';
38
39
    /**
40
     * @var string
41
     */
42
    const DEFAULT_CONFIGURATION_FILE_NAME = 'drupal-debug.yml.dist';
43
44
    /**
45
     * @var bool
46
     */
47
    private static $initialized = false;
48
49
    /**
50
     * @var array|null
51
     */
52
    private static $configurationFilePathInfo = null;
53
54
    /**
55
     * @var array|null
56
     */
57
    private static $processedConfigurations = null;
58
59
    /**
60
     * @var DefaultsConfiguration|null
61
     */
62
    private static $defaultsConfiguration = null;
63
64
    /**
65
     * @var SubstituteOriginalDrupalKernelConfiguration|null
66
     */
67
    private static $substituteOriginalDrupalKernelConfiguration = null;
68
69
    public static function initialize(): void
70
    {
71
        if (self::$initialized) {
72
            throw new \RuntimeException('The configuration should not be initialized twice.');
73
        }
74
75
        self::$initialized = true;
76
77
        $configurationCacheDirectory = \getenv(self::CONFIGURATION_CACHE_DIRECTORY_ENVIRONMENT_VARIABLE_NAME);
78
        if (false === $configurationCacheDirectory) {
79
            $configurationCacheDirectory = \sys_get_temp_dir();
80
        }
81
82
        $configurationFilePathInfo = self::getConfigurationFilePathInfo();
83
        list($configurationFilePath, $configurationFilePathExists) = $configurationFilePathInfo;
84
85
        $fileCache = new FileCache(\sprintf('%s/drupal_debug_configuration.php', $configurationCacheDirectory), new ResourcesCollection(array(
86
            $configurationFilePathExists ? new FileResource($configurationFilePath) : new FileExistenceResource($configurationFilePath),
87
            new FileResource(\sprintf('%s/Configuration.php', __DIR__)),
88
        )));
89
        if ($fileCache->isFresh() && !empty($data = $fileCache->getData())) {
90
            list(
91
                'defaults' => self::$defaultsConfiguration,
92
                'substitute_original_drupal_kernel' => self::$substituteOriginalDrupalKernelConfiguration
93
            ) = \array_map(function ($serializedConfiguration) {
94
                return \unserialize($serializedConfiguration);
95
            }, $data);
96
        } else {
97
            self::$configurationFilePathInfo = $configurationFilePathInfo;
98
99
            $fileCache->invalidate();
100
            $fileCache->write(array(
101
                'defaults' => \serialize(self::getDefaultsConfiguration()),
102
                'substitute_original_drupal_kernel' => \serialize(self::getSubstituteOriginalDrupalKernelConfiguration()),
103
            ));
104
        }
105
    }
106
107
    /**
108
     * @return DefaultsConfiguration
109
     */
110
    public static function getDefaultsConfiguration(): DefaultsConfiguration
111
    {
112
        if (!self::$defaultsConfiguration instanceof DefaultsConfiguration) {
113
            self::process();
114
115
            self::$defaultsConfiguration = new DefaultsConfiguration(self::$processedConfigurations['defaults']);
116
        }
117
118
        return self::$defaultsConfiguration;
119
    }
120
121
    /**
122
     * @return SubstituteOriginalDrupalKernelConfiguration
123
     */
124
    public static function getSubstituteOriginalDrupalKernelConfiguration(): SubstituteOriginalDrupalKernelConfiguration
125
    {
126
        if (!self::$substituteOriginalDrupalKernelConfiguration instanceof SubstituteOriginalDrupalKernelConfiguration) {
127
            self::process();
128
129
            self::$substituteOriginalDrupalKernelConfiguration = new SubstituteOriginalDrupalKernelConfiguration(self::$processedConfigurations['substitute_original_drupal_kernel']);
130
        }
131
132
        return self::$substituteOriginalDrupalKernelConfiguration;
133
    }
134
135
    /**
136
     * @return array
137
     */
138 24
    public static function getConfigurationFilePathInfo(): array
139
    {
140 24
        $possibleConfigurationFilePath = \getenv(self::CONFIGURATION_FILE_PATH_ENVIRONMENT_VARIABLE_NAME);
141 24
        if (false === $possibleConfigurationFilePath) {
142
            // The default configuration file location is the same than the vendor directory.
143
            $possibleAutoloadPaths = array(
144
                // Vendor of a project : Configuration\src\drupal-debug\ekino\autoload.php
145
                \sprintf('%s/../../../../autoload.php', __DIR__),
146
                // Directly this project : Configuration\src\/vendor/autoload.php
147
                \sprintf('%s/../../vendor/autoload.php', __DIR__),
148
                // For other cases (if they exist), please use the dedicated environment variable.
149
            );
150
151
            foreach ($possibleAutoloadPaths as $possibleAutoloadPath) {
152
                if (\is_file($possibleAutoloadPath)) {
153
                    $possibleConfigurationFilePath = \sprintf('%s/../%s', \dirname($possibleAutoloadPath), self::DEFAULT_CONFIGURATION_FILE_NAME);
154
155
                    break;
156
                }
157
            }
158
159
            if (false === $possibleConfigurationFilePath) {
160
                throw new \RuntimeException('The composer autoload.php file could not be found.');
161
            }
162
        }
163
164
        $possibleConfigurationFilePaths = array(
165 24
            $possibleConfigurationFilePath,
166 24
            \rtrim($possibleConfigurationFilePath, '.dist'),
167
        );
168
169 24
        $exists = false;
170 24
        foreach ($possibleConfigurationFilePaths as $possibleConfigurationFilePath) {
171 24
            if (\is_file($possibleConfigurationFilePath)) {
172 16
                $exists = true;
173
174 24
                break;
175
            }
176
        }
177
178
        return array(
179 24
            $possibleConfigurationFilePath,
180 24
            $exists,
181
        );
182
    }
183
184
    private static function process(): void
185
    {
186
        if (!self::$initialized) {
187
            throw new \RuntimeException('The configuration has not been initialized.');
188
        }
189
190
        if (\is_array(self::$processedConfigurations)) {
191
            return;
192
        }
193
194
        $processedConfigurations = (new Processor())->process((new Configuration())->getConfigTreeBuilder()->buildTree(), self::getConfigurationFileContent());
195
        self::$processedConfigurations = self::makeRelativePathsAbsolutes($processedConfigurations);
196
    }
197
198
    /**
199
     * @return array
200
     */
201
    private static function getConfigurationFileContent(): array
202
    {
203
        list($configurationFilePath, $configurationFilePathExists) = self::$configurationFilePathInfo;
204
        if (!$configurationFilePathExists) {
205
            return array();
206
        }
207
208
        $parser = new Parser();
209
        $content = $parser->parseFile($configurationFilePath);
210
        if (!\is_array($content)) {
211
            throw new \RuntimeException('The content of the drupal-debug configuration file should be an array.');
212
        }
213
214
        return $content;
215
    }
216
217
    /**
218
     * @param array $processedConfigurations
219
     *
220
     * @return array
221
     */
222
    private static function makeRelativePathsAbsolutes(array $processedConfigurations): array
223
    {
224
        $filesystem = new Filesystem();
225
226
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
227
228
        $configurationPaths = array(
229
            '[defaults][cache_directory]',
230
            '[defaults][logger][file_path]',
231
            '[substitute_original_drupal_kernel][composer_autoload_file_path]',
232
            '[substitute_original_drupal_kernel][cache_directory]',
233
        );
234
235
        list($configurationFilePath) = self::$configurationFilePathInfo;
236
        $configurationFilePathDirectory = \dirname($configurationFilePath);
237
        foreach ($configurationPaths as $configurationPath) {
238
            if (!$propertyAccessor->isReadable($processedConfigurations, $configurationPath)) {
239
                continue;
240
            }
241
242
            $path = $propertyAccessor->getValue($processedConfigurations, $configurationPath);
243
            if (null === $path || '' === $path) {
244
                continue;
245
            }
246
247
            if (!$filesystem->isAbsolutePath($path)) {
248
                $propertyAccessor->setValue($processedConfigurations, $configurationPath, \sprintf('%s/%s', $configurationFilePathDirectory, $path));
249
            }
250
        }
251
252
        return $processedConfigurations;
253
    }
254
}
255