Passed
Push — master ( 5c08f6...14ca84 )
by Craig
12:46 queued 05:05
created

AjaxUpgradeController::finalizeParameters()   F

Complexity

Conditions 13
Paths 1536

Size

Total Lines 63
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 63
rs 2.8282
c 0
b 0
f 0
cc 13
eloc 35
nc 1536
nop 0

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
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zikula\Bundle\CoreInstallerBundle\Controller;
13
14
use RandomLib\Factory;
15
use Symfony\Component\DependencyInjection\ContainerInterface;
16
use Symfony\Component\HttpFoundation\JsonResponse;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\Yaml\Yaml;
19
use Zikula\BlocksModule\Entity\BlockEntity;
20
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
21
use Zikula\Bundle\CoreBundle\YamlDumper;
22
use Zikula\Core\CoreEvents;
23
use Zikula\ExtensionsModule\Api\VariableApi;
24
use Zikula\ThemeModule\Entity\Repository\ThemeEntityRepository;
25
26
/**
27
 * Class AjaxUpgradeController
28
 */
29
class AjaxUpgradeController extends AbstractController
30
{
31
    /**
32
     * @var YamlDumper
33
     */
34
    private $yamlManager;
35
36
    /**
37
     * @var string the currently installed core version
38
     */
39
    private $currentVersion;
40
41
    /**
42
     * AjaxUpgradeController constructor.
43
     * @param ContainerInterface $container
44
     */
45
    public function __construct(ContainerInterface $container)
46
    {
47
        parent::__construct($container);
48
        $originalParameters = Yaml::parse(file_get_contents($this->container->get('kernel')->getRootDir() . '/config/parameters.yml'));
49
        $this->yamlManager = new YamlDumper($this->container->get('kernel')->getRootDir() . '/config', 'custom_parameters.yml');
50
        // load and set new default values from the original parameters.yml file into the custom_parameters.yml file.
51
        $this->yamlManager->setParameters(array_merge($originalParameters['parameters'], $this->yamlManager->getParameters()));
52
        $this->currentVersion = $this->container->getParameter(ZikulaKernel::CORE_INSTALLED_VERSION_PARAM);
53
    }
54
55
    public function ajaxAction(Request $request)
56
    {
57
        $stage = $request->request->get('stage');
58
        $this->yamlManager->setParameter('upgrading', true);
59
        $status = $this->executeStage($stage);
60
        $response = ['status' => (bool)$status];
61
        if (is_array($status)) {
62
            $response['results'] = $status;
63
        }
64
65
        return new JsonResponse($response);
66
    }
67
68
    public function commandLineAction($stage)
69
    {
70
        $this->yamlManager->setParameter('upgrading', true);
71
72
        return $this->executeStage($stage);
73
    }
74
75
    private function executeStage($stageName)
76
    {
77
        switch ($stageName) {
78
            case "loginadmin":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal loginadmin does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
79
                $params = $this->decodeParameters($this->yamlManager->getParameters());
80
81
                return $this->loginAdmin($params);
82
            case "upgrade_event":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal upgrade_event does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
83
                return $this->fireEvent(CoreEvents::CORE_UPGRADE_PRE_MODULE, ['currentVersion' => $this->currentVersion]);
84
            case "upgrademodules":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal upgrademodules does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
85
                $result = $this->upgradeModules();
86
                if (count($result) === 0) {
87
                    return true;
88
                }
89
90
                return $result;
91
            case "regenthemes":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal regenthemes does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
92
                return $this->regenerateThemes();
93
            case "versionupgrade":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal versionupgrade does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
94
                return $this->versionUpgrade();
95
            case "finalizeparameters":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal finalizeparameters does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
96
                return $this->finalizeParameters();
97
            case "clearcaches":
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal clearcaches does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
98
                return $this->clearCaches();
99
        }
100
101
        return true;
102
    }
103
104
    /**
105
     * Attempt to upgrade ALL the core modules. Some will need it, some will not.
106
     * Modules that do not need upgrading return TRUE as a result of the upgrade anyway.
107
     * @return array
108
     */
109
    private function upgradeModules()
110
    {
111
        $coreModulesInPriorityUpgradeOrder = [
112
            'ZikulaExtensionsModule',
113
            'ZikulaUsersModule',
114
            'ZikulaZAuthModule',
115
            'ZikulaGroupsModule',
116
            'ZikulaPermissionsModule',
117
            'ZikulaAdminModule',
118
            'ZikulaBlocksModule',
119
            'ZikulaThemeModule',
120
            'ZikulaSettingsModule',
121
            'ZikulaCategoriesModule',
122
            'ZikulaSecurityCenterModule',
123
            'ZikulaRoutesModule',
124
            'ZikulaMailerModule',
125
            'ZikulaSearchModule',
126
            'ZikulaMenuModule',
127
        ];
128
        $result = [];
129
        foreach ($coreModulesInPriorityUpgradeOrder as $moduleName) {
130
            $extensionEntity = $this->container->get('zikula_extensions_module.extension_repository')->get($moduleName);
131
            if (isset($extensionEntity)) {
132
                $result[$moduleName] = $this->container->get('zikula_extensions_module.extension_helper')->upgrade($extensionEntity);
133
            }
134
        }
135
136
        return $result;
137
    }
138
139
    private function regenerateThemes()
140
    {
141
        // regenerate the themes list
142
        $this->container->get('zikula_theme_module.helper.bundle_sync_helper')->regenerate();
143
        // set all themes as active @todo this is probably overkill
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
144
        $themes = $this->container->get('zikula_theme_module.theme_entity.repository')->findAll();
145
        /** @var \Zikula\ThemeModule\Entity\ThemeEntity $theme */
146
        foreach ($themes as $theme) {
147
            $theme->setState(ThemeEntityRepository::STATE_ACTIVE);
148
        }
149
        $this->container->get('doctrine')->getManager()->flush();
150
151
        return true;
152
    }
153
154
    private function versionUpgrade()
155
    {
156
        $doctrine = $this->container->get('doctrine');
157
        /**
158
         * NOTE: There are *intentionally* no `break` statements within each case here so that the process continues
159
         * through each case until the end.
160
         */
161
        switch ($this->currentVersion) {
162
            case '1.4.3':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
163
                $this->installModule('ZikulaMenuModule');
164
                $this->reSyncAndActivateModules();
165
                $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
166
            case '1.4.4':
167
                // nothing
168
            case '1.4.5':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
169
                // Menu module was introduced in 1.4.4 but not installed on upgrade
170
                $schemaManager = $doctrine->getConnection()->getSchemaManager();
171
                if (!$schemaManager->tablesExist(['menu_items'])) {
172
                    $this->installModule('ZikulaMenuModule');
173
                    $this->reSyncAndActivateModules();
174
                    $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
175
                }
176
            case '1.4.6':
177
                // nothing needed
178
            case '1.4.7':
179
                // nothing needed
180
            case '1.5.0':
181
                // nothing needed
182
            case '1.9.99':
183
                // upgrades required for 2.0.0
184
                foreach (['objectdata_attributes', 'objectdata_log', 'objectdata_meta', 'workflows'] as $table) {
185
                    $sql = "DROP TABLE $table;";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $table instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
186
                    $connection = $doctrine->getConnection();
187
                    $stmt = $connection->prepare($sql);
188
                    $stmt->execute();
189
                    $stmt->closeCursor();
190
                }
191
                $variableApi = $this->container->get('zikula_extensions_module.api.variable');
192
                $variableApi->del(VariableApi::CONFIG, 'metakeywords');
193
                $variableApi->del(VariableApi::CONFIG, 'startpage');
194
                $variableApi->del(VariableApi::CONFIG, 'startfunc');
195
                $variableApi->del(VariableApi::CONFIG, 'starttype');
196
                if ($this->container->getParameter('datadir') == 'userdata') {
197
                    $this->yamlManager->setParameter('datadir', 'web/uploads');
0 ignored issues
show
Documentation introduced by
'web/uploads' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
198
                    $fs = $this->container->get('filesystem');
199
                    $src = realpath(__DIR__ . '/../../../../../');
200
                    try {
201
                        if ($fs->exists($src . '/userdata')) {
202
                            $fs->mirror($src . '/userdata', $src . '/web/uploads');
203
                        }
204
                    } catch (\Exception $e) {
205
                        $this->container->get('session')->getFlashBag()->add('info', $this->translator->__('Attempt to copy files from `userdata` to `web/uploads` failed. You must manually copy the contents.'));
206
                    }
207
                }
208
                // remove legacy blocks
209
                $blocksToRemove = $doctrine->getRepository(BlockEntity::class)->findBy(['blocktype' => ['Extmenu', 'Menutree', 'Menu']]);
210
                foreach ($blocksToRemove as $block) {
211
                    $doctrine->getManager()->remove($block);
212
                }
213
                $doctrine->getManager()->flush();
214
        }
215
216
        // always do this
217
        $this->reSyncAndActivateModules();
218
219
        return true;
220
    }
221
222
    private function finalizeParameters()
223
    {
224
        $variableApi = $this->container->get('zikula_extensions_module.api.variable');
225
        // Set the System Identifier as a unique string.
226
        if (!$variableApi->get(VariableApi::CONFIG, 'system_identifier')) {
227
            $variableApi->set(VariableApi::CONFIG, 'system_identifier', str_replace('.', '', uniqid(rand(1000000000, 9999999999), true)));
228
        }
229
230
        // add new configuration parameters
231
        $params = $this->yamlManager->getParameters();
232
        unset($params['username'], $params['password']);
233
        $RandomLibFactory = new Factory();
234
        $generator = $RandomLibFactory->getMediumStrengthGenerator();
235
236
        if (!isset($params['secret']) || ($params['secret'] == 'ThisTokenIsNotSoSecretChangeIt')) {
237
            $params['secret'] = $generator->generateString(50);
238
        }
239
        if (!isset($params['url_secret'])) {
240
            $params['url_secret'] = $generator->generateString(10);
241
        }
242
        // Configure the Request Context
243
        // see http://symfony.com/doc/current/cookbook/console/sending_emails.html#configuring-the-request-context-globally
244
        $request = $this->container->get('request_stack')->getMasterRequest();
245
        $hostFromRequest = isset($request) ? $request->getHost() : null;
246
        $basePathFromRequest = isset($request) ? $request->getBasePath() : null;
247
        $params['router.request_context.host'] = isset($params['router.request_context.host']) ? $params['router.request_context.host'] : $hostFromRequest;
248
        $params['router.request_context.scheme'] = isset($params['router.request_context.scheme']) ? $params['router.request_context.scheme'] : 'http';
249
        $params['router.request_context.base_url'] = isset($params['router.request_context.base_url']) ? $params['router.request_context.base_url'] : $basePathFromRequest;
250
251
        // set currently installed version into parameters
252
        $params[ZikulaKernel::CORE_INSTALLED_VERSION_PARAM] = ZikulaKernel::VERSION;
253
254
        // disable asset combination on upgrades
255
        $params['zikula_asset_manager.combine'] = false;
256
257
        // always try to update the database_server_version param
258
        try {
259
            $dbh = new \PDO("$params[database_driver]:host=$params[database_host];dbname=$params[database_name]", $params['database_user'], $params['database_password']);
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $params instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
260
            $params['database_server_version'] = $dbh->getAttribute(\PDO::ATTR_SERVER_VERSION);
261
        } catch (\Exception $e) {
262
            // do nothing on fail
263
        }
264
265
        unset($params['upgrading']);
266
        $this->yamlManager->setParameters($params);
267
268
        // store the recent version in a config var for later usage. This enables us to determine the version we are upgrading from
269
        $variableApi->set(VariableApi::CONFIG, 'Version_Num', ZikulaKernel::VERSION);
270
        $variableApi->set(VariableApi::CONFIG, 'Version_Sub', ZikulaKernel::VERSION_SUB);
271
272
        // set the 'start' page information to empty to avoid missing module errors.
273
        $variableApi->set(VariableApi::CONFIG, 'startController', '');
274
        $variableApi->set(VariableApi::CONFIG, 'startargs', '');
275
        // on upgrade, if a user doesn't add their custom theme back to the /theme dir, it should be reset to a core theme, if available.
276
        $defaultTheme = $variableApi->getSystemVar('Default_Theme');
277
        if (!$this->container->get('kernel')->isBundle($defaultTheme)
278
            && $this->container->get('kernel')->isBundle('ZikulaBootstrapTheme')
279
        ) {
280
            $variableApi->set(VariableApi::CONFIG, 'Default_Theme', 'ZikulaBootstrapTheme');
281
        }
282
283
        return true;
284
    }
285
286
    private function clearCaches()
287
    {
288
        // clear cache with zikula's method
289
        $cacheClearer = $this->container->get('zikula.cache_clearer');
290
        $cacheClearer->clear('symfony');
291
        // use full symfony cache_clearer not zikula's to clear entire cache and set for warmup
292
        // console commands always run in `dev` mode but site should be `prod` mode. clear both for good measure.
293
        $this->container->get('cache_clearer')->clear('dev');
294
        $this->container->get('cache_clearer')->clear('prod');
295
        if (!in_array($this->container->getParameter('env'), ['dev', 'prod'])) {
296
            // this is just in case anyone ever creates a mode that isn't dev|prod
297
            $this->container->get('cache_clearer')->clear($this->container->getParameter('env'));
298
        }
299
300
        return true;
301
    }
302
}
303