Completed
Pull Request — master (#4433)
by Craig
04:45
created

ParameterHelper   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 99
c 4
b 1
f 0
dl 0
loc 215
rs 10
wmc 27

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A resetLegacyParams() 0 19 1
A initializeParameters() 0 8 1
A writeEnvVars() 0 19 6
A finalizeParameters() 0 31 4
A decodeParameters() 0 9 4
A writeEncodedParameters() 0 11 4
A getYamlHelper() 0 3 1
A configureRequestContext() 0 9 4
A setMailerData() 0 6 1
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(): YamlDumper
94
    {
95
        return new YamlDumper($this->configDir, 'temp_params.yaml');
0 ignored issues
show
Deprecated Code introduced by
The class Zikula\Bundle\CoreBundle\YamlDumper has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

95
        return /** @scrutinizer ignore-deprecated */ new YamlDumper($this->configDir, 'temp_params.yaml');
Loading history...
96
    }
97
98
    public function initializeParameters(array $paramsToMerge = []): bool
99
    {
100
        $yamlHelper = $this->getYamlHelper();
101
        $params = array_merge($yamlHelper->getParameters(), $paramsToMerge);
102
        $yamlHelper->setParameters($params);
103
        $this->cacheClearer->clear('symfony.config');
104
105
        return true;
106
    }
107
108
    /**
109
     * @throws IOExceptionInterface If .env.local could not be dumped
110
     */
111
    public function finalizeParameters(): bool
112
    {
113
        $yamlHelper = $this->getYamlHelper();
114
        $params = $this->decodeParameters($yamlHelper->getParameters());
115
116
        $this->variableApi->getAll(VariableApi::CONFIG); // forces initialization of API
117
        if (!isset($params['upgrading']) || !$params['upgrading']) {
118
            $this->variableApi->set(VariableApi::CONFIG, 'locale', $params['locale']);
119
            // Set the System Identifier as a unique string.
120
            if (!$this->variableApi->get(VariableApi::CONFIG, 'system_identifier')) {
121
                $this->variableApi->set(VariableApi::CONFIG, 'system_identifier', str_replace('.', '', uniqid((string) (random_int(1000000000, 9999999999)), true)));
122
            }
123
            // add admin email as site email
124
            $this->variableApi->set(VariableApi::CONFIG, 'adminmail', $params['email']);
125
            $this->setMailerData($params);
126
            $this->configureRequestContext($params);
127
        }
128
129
        $params = array_diff_key($params, array_flip($this->encodedParameterNames)); // remove all encoded params
130
131
        // store the recent version in a config var for later usage. This enables us to determine the version we are upgrading from
132
        $this->variableApi->set(VariableApi::CONFIG, 'Version_Num', ZikulaKernel::VERSION);
133
134
        $this->writeEnvVars($params);
135
136
        $yamlHelper->deleteFile();
137
138
        // clear the cache
139
        $this->cacheClearer->clear('symfony.config');
140
141
        return true;
142
    }
143
144
    /**
145
     * Configure the Request Context
146
     * see https://symfony.com/doc/current/routing.html#generating-urls-in-commands
147
     * This is needed because emails are sent from CLI requiring routes to be built
148
     */
149
    private function configureRequestContext(array &$params): void
150
    {
151
        $request = $this->requestStack->getMasterRequest();
152
        $hostFromRequest = isset($request) ? $request->getHost() : 'localhost';
153
        $schemeFromRequest = isset($request) ? $request->getScheme() : 'http';
154
        $basePathFromRequest = isset($request) ? $request->getBasePath() : null;
155
        $params['router.request_context.host'] = $params['router.request_context.host'] ?? $hostFromRequest;
156
        $params['router.request_context.scheme'] = $params['router.request_context.scheme'] ?? $schemeFromRequest;
157
        $params['router.request_context.base_url'] = $params['router.request_context.base_url'] ?? $basePathFromRequest;
158
    }
159
160
    /**
161
     * @param array $params values from upgrade
162
     */
163
    private function writeEnvVars(array &$params): void
164
    {
165
        $randomLibFactory = new Factory();
166
        $generator = $randomLibFactory->getMediumStrengthGenerator();
167
        $secret = isset($params['secret']) && !empty($params['secret']) && '%env(APP_SECRET)%' !== $params['secret']
168
            ? $params['secret']
169
            : $generator->generateString(50)
170
        ;
171
        $vars = [
172
            'APP_ENV' => $params['env'] ?? 'prod',
173
            'APP_DEBUG' => isset($params['debug']) ? (int) ($params['debug']) : 0,
174
            'APP_SECRET' => '!\'' . $secret . '\'',
175
            'ZIKULA_INSTALLED' => '\'' . ZikulaKernel::VERSION . '\''
176
        ];
177
        if (isset($params['router.request_context.host'])) {
178
            $vars['DEFAULT_URI'] = sprintf('!%s://%s%s', $params['router.request_context.scheme'], $params['router.request_context.host'], $params['router.request_context.base_url']);
179
            unset($params['router.request_context.scheme'], $params['router.request_context.host'], $params['router.request_context.base_url']);
180
        }
181
        (new LocalDotEnvHelper($this->projectDir))->writeLocalEnvVars($vars);
182
    }
183
184
    private function resetLegacyParams(array &$params): void
0 ignored issues
show
Unused Code introduced by
The method resetLegacyParams() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
185
    {
186
        unset(
187
            $params['temp_dir'],
188
            $params['system.chmod_dir'],
189
            $params['url_secret'],
190
            $params['umask'],
191
            $params['env'],
192
            $params['debug'],
193
            $params['secret'],
194
            $params['database_driver'],
195
            $params['database_host'],
196
            $params['database_port'],
197
            $params['database_name'],
198
            $params['database_user'],
199
            $params['database_password'],
200
            $params['database_path'],
201
            $params['database_socket'],
202
            $params['database_server_version']
203
        );
204
    }
205
206
    /**
207
     * Write params to file as encoded values.
208
     *
209
     * @throws AbortStageException
210
     */
211
    public function writeEncodedParameters(array $data): void
212
    {
213
        $yamlHelper = $this->getYamlHelper();
214
        foreach ($data as $k => $v) {
215
            $data[$k] = is_string($v) ? base64_encode($v) : $v; // encode so values are 'safe' for json
216
        }
217
        $params = array_merge($yamlHelper->getParameters(), $data);
218
        try {
219
            $yamlHelper->setParameters($params);
220
        } catch (IOException $exception) {
221
            throw new AbortStageException(sprintf('Cannot write parameters to %s file.', 'services_custom.yaml'));
222
        }
223
    }
224
225
    /**
226
     * Remove base64 encoding for parameters.
227
     */
228
    public function decodeParameters(array $params = []): array
229
    {
230
        foreach ($this->encodedParameterNames as $parameterName) {
231
            if (!empty($params[$parameterName])) {
232
                $params[$parameterName] = is_string($params[$parameterName]) ? base64_decode($params[$parameterName]) : $params[$parameterName];
233
            }
234
        }
235
236
        return $params;
237
    }
238
239
    private function setMailerData(array $params): void
240
    {
241
        // params have already been decoded
242
        $mailerParams = array_intersect_key($params, array_flip($this->encodedParameterNames));
243
        unset($mailerParams['mailer_key'], $mailerParams['password'], $mailerParams['username'], $mailerParams['email']);
244
        $this->variableApi->setAll('ZikulaMailerModule', $mailerParams);
245
    }
246
}
247