Completed
Push — master ( a570c6...85a69a )
by Craig
05:26
created

ParameterHelper::writeEncodedParameters()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
c 0
b 0
f 0
nc 6
nop 1
dl 0
loc 11
rs 10
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
            $params['database_driver'] = mb_substr($params['database_driver'], 4); // remove pdo_ prefix
164
            (new DbCredsHelper($this->projectDir))->writeDatabaseDsn($params);
165
            $this->resetLegacyParams($params);
166
        }
167
168
        // write parameters into config/services_custom.yaml
169
        $yamlHelper->setParameters($params);
170
171
        // clear the cache
172
        $this->cacheClearer->clear('symfony.config');
173
174
        return true;
175
    }
176
177
    /**
178
     * @param array $params values from upgrade
179
     */
180
    private function writeEnvVars(array $params)
181
    {
182
        $randomLibFactory = new Factory();
183
        $generator = $randomLibFactory->getMediumStrengthGenerator();
184
        $vars = [
185
            'APP_ENV' => $params['env'] ?? 'prod',
186
            'APP_DEBUG' => isset($params['debug']) ? (int) ($params['debug']) : 1,
187
            'APP_SECRET' => '!\'' . ($params['secret'] ?? $generator->generateString(50)) . '\'',
188
            'ZIKULA_INSTALLED' => '\'' . ZikulaKernel::VERSION . '\''
189
        ];
190
        (new LocalDotEnvHelper($this->projectDir))->writeLocalEnvVars($vars);
191
    }
192
193
    private function resetLegacyParams(array &$params): void
194
    {
195
        unset(
196
            $params['temp_dir'],
197
            $params['system.chmod_dir'],
198
            $params['url_secret'],
199
            $params['umask'],
200
            $params['env'],
201
            $params['debug'],
202
            $params['secret'],
203
            $params['database_driver'],
204
            $params['database_host'],
205
            $params['database_port'],
206
            $params['database_name'],
207
            $params['database_user'],
208
            $params['database_password'],
209
            $params['database_path'],
210
            $params['database_socket'],
211
            $params['database_server_version']
212
        );
213
214
        $params['installed'] = '%env(ZIKULA_INSTALLED)%';
215
        $params['zikula_asset_manager.combine'] = false;
216
    }
217
218
    /**
219
     * Write params to file as encoded values.
220
     *
221
     * @throws AbortStageException
222
     */
223
    public function writeEncodedParameters(array $data): void
224
    {
225
        $yamlHelper = $this->getYamlHelper();
226
        foreach ($data as $k => $v) {
227
            $data[$k] = is_string($v) ? base64_encode($v) : $v; // encode so values are 'safe' for json
228
        }
229
        $params = array_merge($yamlHelper->getParameters(), $data);
230
        try {
231
            $yamlHelper->setParameters($params);
232
        } catch (IOException $exception) {
233
            throw new AbortStageException(sprintf('Cannot write parameters to %s file.', 'services_custom.yaml'));
234
        }
235
    }
236
237
    /**
238
     * Remove base64 encoding for parameters.
239
     */
240
    public function decodeParameters(array $params = []): array
241
    {
242
        foreach ($this->encodedParameterNames as $parameterName) {
243
            if (!empty($params[$parameterName])) {
244
                $params[$parameterName] = is_string($params[$parameterName]) ? base64_decode($params[$parameterName]) : $params[$parameterName];
245
            }
246
        }
247
248
        return $params;
249
    }
250
251
    private function setMailerData(array $params): void
252
    {
253
        // params have already been decoded
254
        $mailerParams = array_intersect_key($params, array_flip($this->encodedParameterNames));
255
        unset($mailerParams['mailer_key'], $mailerParams['password'], $mailerParams['username'], $mailerParams['email']);
256
        $this->variableApi->setAll('ZikulaMailerModule', $mailerParams);
257
    }
258
}
259