Completed
Push — master ( f5cbef...dba98a )
by Craig
09:56 queued 04:13
created

ParameterHelper   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 105
dl 0
loc 226
rs 9.92
c 4
b 1
f 0
wmc 31

10 Methods

Rating   Name   Duplication   Size   Complexity  
A reInitParameters() 0 8 1
A initializeParameters() 0 8 1
A __construct() 0 13 1
A getYamlHelper() 0 5 2
A decodeParameters() 0 9 4
A writeEncodedParameters() 0 11 4
A setMailerData() 0 6 1
A resetLegacyParams() 0 19 1
A writeEnvVars() 0 15 5
B finalizeParameters() 0 47 11
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
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 Zikula\Bundle\CoreInstallerBundle\Helper;
15
16
use RandomLib\Factory;
17
use Symfony\Component\Filesystem\Exception\IOException;
18
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\Yaml\Yaml;
21
use Zikula\Bundle\CoreBundle\CacheClearer;
22
use Zikula\Bundle\CoreBundle\Helper\LocalDotEnvHelper;
23
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
24
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
25
use Zikula\Bundle\CoreBundle\YamlDumper;
26
use Zikula\Component\Wizard\AbortStageException;
27
use Zikula\ExtensionsModule\Api\ApiInterface\VariableApiInterface;
28
use Zikula\ExtensionsModule\Api\VariableApi;
29
30
class ParameterHelper
31
{
32
    /**
33
     * @var string
34
     */
35
    private $configDir;
36
37
    /**
38
     * @var string
39
     */
40
    private $projectDir;
41
42
    /**
43
     * @var VariableApiInterface
44
     */
45
    private $variableApi;
46
47
    /**
48
     * @var CacheClearer
49
     */
50
    private $cacheClearer;
51
52
    /**
53
     * @var RequestStack
54
     */
55
    private $requestStack;
56
57
    /**
58
     * @var ZikulaHttpKernelInterface
59
     */
60
    private $kernel;
61
62
    private $encodedParameterNames = [
63
        'password',
64
        'username',
65
        'email',
66
        'transport',
67
        'mailer_id',
68
        'mailer_key',
69
        'host',
70
        'port',
71
        'customParameters',
72
        'enableLogging'
73
    ];
74
75
    /**
76
     * ParameterHelper constructor.
77
     */
78
    public function __construct(
79
        string $projectDir,
80
        VariableApiInterface $variableApi,
81
        CacheClearer $cacheClearer,
82
        RequestStack $requestStack,
83
        ZikulaHttpKernelInterface $kernel
84
    ) {
85
        $this->configDir = $projectDir . '/config';
86
        $this->projectDir = $projectDir;
87
        $this->variableApi = $variableApi;
88
        $this->cacheClearer = $cacheClearer;
89
        $this->requestStack = $requestStack;
90
        $this->kernel = $kernel;
91
    }
92
93
    public function getYamlHelper(bool $initCopy = false): YamlDumper
94
    {
95
        $copyFile = $initCopy ? 'services.yaml' : null;
96
97
        return new YamlDumper($this->configDir, 'services_custom.yaml', $copyFile);
98
    }
99
100
    public function initializeParameters(array $paramsToMerge = []): bool
101
    {
102
        $yamlHelper = $this->getYamlHelper(true);
103
        $params = array_merge($yamlHelper->getParameters(), $paramsToMerge);
104
        $yamlHelper->setParameters($params);
105
        $this->cacheClearer->clear('symfony.config');
106
107
        return true;
108
    }
109
110
    /**
111
     * Load and set new default values from the original services.yaml file into the services_custom.yaml file.
112
     */
113
    public function reInitParameters(): bool
114
    {
115
        $originalParameters = Yaml::parse(file_get_contents($this->kernel->getProjectDir() . '/config/services.yaml'));
116
        $yamlHelper = $this->getYamlHelper();
117
        $yamlHelper->setParameters(array_merge($originalParameters['parameters'], $yamlHelper->getParameters()));
118
        $this->cacheClearer->clear('symfony.config');
119
120
        return true;
121
    }
122
123
    /**
124
     * @throws IOExceptionInterface If .env.local could not be dumped
125
     */
126
    public function finalizeParameters(bool $configureRequestContext = true): bool
127
    {
128
        $yamlHelper = $this->getYamlHelper();
129
        $params = $this->decodeParameters($yamlHelper->getParameters());
130
131
        $this->variableApi->getAll(VariableApi::CONFIG); // forces initialization of API
132
        if (!isset($params['upgrading']) || !$params['upgrading']) {
133
            $this->variableApi->set(VariableApi::CONFIG, 'locale', $params['locale']);
134
            // Set the System Identifier as a unique string.
135
            if (!$this->variableApi->get(VariableApi::CONFIG, 'system_identifier')) {
136
                $this->variableApi->set(VariableApi::CONFIG, 'system_identifier', str_replace('.', '', uniqid((string) (random_int(1000000000, 9999999999)), true)));
137
            }
138
            // add admin email as site email
139
            $this->variableApi->set(VariableApi::CONFIG, 'adminmail', $params['email']);
140
            $this->setMailerData($params);
141
        }
142
143
        $params = array_diff_key($params, array_flip($this->encodedParameterNames)); // remove all encoded params
144
        $params['datadir'] = !empty($params['datadir']) ? $params['datadir'] : 'public/uploads';
145
146
        if ($configureRequestContext) {
147
            // Configure the Request Context
148
            // see http://symfony.com/doc/current/cookbook/console/sending_emails.html#configuring-the-request-context-globally
149
            $request = $this->requestStack->getMasterRequest();
150
            $hostFromRequest = isset($request) ? $request->getHost() : null;
151
            $schemeFromRequest = isset($request) ? $request->getScheme() : 'http';
152
            $basePathFromRequest = isset($request) ? $request->getBasePath() : null;
153
            $params['router.request_context.host'] = $params['router.request_context.host'] ?? $hostFromRequest;
154
            $params['router.request_context.scheme'] = $params['router.request_context.scheme'] ?? $schemeFromRequest;
155
            $params['router.request_context.base_url'] = $params['router.request_context.base_url'] ?? $basePathFromRequest;
156
        }
157
        // store the recent version in a config var for later usage. This enables us to determine the version we are upgrading from
158
        $this->variableApi->set(VariableApi::CONFIG, 'Version_Num', ZikulaKernel::VERSION);
159
160
        $this->writeEnvVars($params);
161
162
        if (isset($params['upgrading']) && $params['upgrading']) {
163
            $this->resetLegacyParams($params);
164
        }
165
166
        // write parameters into config/services_custom.yaml
167
        $yamlHelper->setParameters($params);
168
169
        // clear the cache
170
        $this->cacheClearer->clear('symfony.config');
171
172
        return true;
173
    }
174
175
    /**
176
     * @param array $params values from upgrade
177
     */
178
    private function writeEnvVars(array $params)
179
    {
180
        $randomLibFactory = new Factory();
181
        $generator = $randomLibFactory->getMediumStrengthGenerator();
182
        $secret = isset($params['secret']) && !empty($params['secret']) && '%env(APP_SECRET)%' !== $params['secret']
183
            ? $params['secret']
184
            : $generator->generateString(50)
185
        ;
186
        $vars = [
187
            'APP_ENV' => $params['env'] ?? 'prod',
188
            'APP_DEBUG' => isset($params['debug']) ? (int) ($params['debug']) : 0,
189
            'APP_SECRET' => '!\'' . $secret . '\'',
190
            'ZIKULA_INSTALLED' => '\'' . ZikulaKernel::VERSION . '\''
191
        ];
192
        (new LocalDotEnvHelper($this->projectDir))->writeLocalEnvVars($vars);
193
    }
194
195
    private function resetLegacyParams(array &$params): void
196
    {
197
        unset(
198
            $params['temp_dir'],
199
            $params['system.chmod_dir'],
200
            $params['url_secret'],
201
            $params['umask'],
202
            $params['env'],
203
            $params['debug'],
204
            $params['secret'],
205
            $params['database_driver'],
206
            $params['database_host'],
207
            $params['database_port'],
208
            $params['database_name'],
209
            $params['database_user'],
210
            $params['database_password'],
211
            $params['database_path'],
212
            $params['database_socket'],
213
            $params['database_server_version']
214
        );
215
    }
216
217
    /**
218
     * Write params to file as encoded values.
219
     *
220
     * @throws AbortStageException
221
     */
222
    public function writeEncodedParameters(array $data): void
223
    {
224
        $yamlHelper = $this->getYamlHelper();
225
        foreach ($data as $k => $v) {
226
            $data[$k] = is_string($v) ? base64_encode($v) : $v; // encode so values are 'safe' for json
227
        }
228
        $params = array_merge($yamlHelper->getParameters(), $data);
229
        try {
230
            $yamlHelper->setParameters($params);
231
        } catch (IOException $exception) {
232
            throw new AbortStageException(sprintf('Cannot write parameters to %s file.', 'services_custom.yaml'));
233
        }
234
    }
235
236
    /**
237
     * Remove base64 encoding for parameters.
238
     */
239
    public function decodeParameters(array $params = []): array
240
    {
241
        foreach ($this->encodedParameterNames as $parameterName) {
242
            if (!empty($params[$parameterName])) {
243
                $params[$parameterName] = is_string($params[$parameterName]) ? base64_decode($params[$parameterName]) : $params[$parameterName];
244
            }
245
        }
246
247
        return $params;
248
    }
249
250
    private function setMailerData(array $params): void
251
    {
252
        // params have already been decoded
253
        $mailerParams = array_intersect_key($params, array_flip($this->encodedParameterNames));
254
        unset($mailerParams['mailer_key'], $mailerParams['password'], $mailerParams['username'], $mailerParams['email']);
255
        $this->variableApi->setAll('ZikulaMailerModule', $mailerParams);
256
    }
257
}
258