Completed
Push — master ( 1ff674...fe6f28 )
by Craig
05:53
created

AjaxUpgradeController::from141to142()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 3
nop 0
dl 0
loc 15
rs 9.2
c 0
b 0
f 0
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\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
20
use Zikula\Bundle\CoreBundle\YamlDumper;
21
use Zikula\ExtensionsModule\Api\VariableApi;
22
use Zikula\ThemeModule\Entity\Repository\ThemeEntityRepository;
23
24
/**
25
 * Class AjaxUpgradeController
26
 */
27
class AjaxUpgradeController extends AbstractController
28
{
29
    /**
30
     * @var YamlDumper
31
     */
32
    private $yamlManager;
33
34
    /**
35
     * @var string the currently installed core version
36
     */
37
    private $currentVersion;
38
39
    /**
40
     * AjaxUpgradeController constructor.
41
     * @param ContainerInterface $container
42
     */
43
    public function __construct(ContainerInterface $container)
44
    {
45
        parent::__construct($container);
46
        $originalParameters = Yaml::parse(file_get_contents($this->container->get('kernel')->getRootDir() .'/config/parameters.yml'));
47
        $this->yamlManager = new YamlDumper($this->container->get('kernel')->getRootDir() .'/config', 'custom_parameters.yml');
48
        // load and set new default values from the original parameters.yml file into the custom_parameters.yml file.
49
        $this->yamlManager->setParameters(array_merge($originalParameters['parameters'], $this->yamlManager->getParameters()));
50
        $this->currentVersion = $this->container->getParameter(ZikulaKernel::CORE_INSTALLED_VERSION_PARAM);
51
    }
52
53
    public function ajaxAction(Request $request)
54
    {
55
        $stage = $request->request->get('stage');
56
        $this->container->setParameter('upgrading', true);
57
        $status = $this->executeStage($stage);
58
        $response = ['status' => (bool) $status];
59
        if (is_array($status)) {
60
            $response['results'] = $status;
61
        }
62
63
        return new JsonResponse($response);
64
    }
65
66
    public function commandLineAction($stage)
67
    {
68
        $this->container->setParameter('upgrading', true);
69
70
        return $this->executeStage($stage);
71
    }
72
73
    private function executeStage($stageName)
74
    {
75
        switch ($stageName) {
76
            case "loginadmin":
77
                $params = $this->decodeParameters($this->yamlManager->getParameters());
78
79
                return $this->loginAdmin($params);
80
            case "upgrademodules":
81
                $result = $this->upgradeModules();
82
                if (count($result) === 0) {
83
                    return true;
84
                }
85
86
                return $result;
87
            case "installroutes":
88
                if (version_compare(ZikulaKernel::VERSION, '1.4.0', '>') && version_compare($this->currentVersion, '1.4.0', '>=')) {
89
                    // this stage is not necessary to upgrade from 1.4.0 -> 1.4.x
90
                    return true;
91
                }
92
                $this->installModule('ZikulaRoutesModule');
93
                $this->reSyncAndActivateModules();
94
                $this->setModuleCategory('ZikulaRoutesModule', $this->translator->__('System'));
95
96
                return true;
97
            case "regenthemes":
98
                return $this->regenerateThemes();
99
            case "versionupgrade":
100
                return $this->versionUpgrade();
101
            case "finalizeparameters":
102
                return $this->finalizeParameters();
103
            case "clearcaches":
104
                return $this->clearCaches();
105
        }
106
107
        return true;
108
    }
109
110
    /**
111
     * Attempt to upgrade ALL the core modules. Some will need it, some will not.
112
     * Modules that do not need upgrading return TRUE as a result of the upgrade anyway.
113
     * @return array
114
     */
115
    private function upgradeModules()
116
    {
117
        $coreModulesInPriorityUpgradeOrder = [
118
            'ZikulaExtensionsModule',
119
            'ZikulaUsersModule',
120
            'ZikulaZAuthModule',
121
            'ZikulaGroupsModule',
122
            'ZikulaPermissionsModule',
123
            'ZikulaAdminModule',
124
            'ZikulaBlocksModule',
125
            'ZikulaThemeModule',
126
            'ZikulaSettingsModule',
127
            'ZikulaCategoriesModule',
128
            'ZikulaSecurityCenterModule',
129
            'ZikulaRoutesModule',
130
            'ZikulaMailerModule',
131
            'ZikulaSearchModule',
132
            'ZikulaMenuModule',
133
        ];
134
        $result = [];
135
        foreach ($coreModulesInPriorityUpgradeOrder as $moduleName) {
136
            $extensionEntity = $this->container->get('zikula_extensions_module.extension_repository')->get($moduleName);
137
            if (isset($extensionEntity)) {
138
                $result[$moduleName] = $this->container->get('zikula_extensions_module.extension_helper')->upgrade($extensionEntity);
139
            }
140
        }
141
142
        return $result;
143
    }
144
145
    private function regenerateThemes()
146
    {
147
        // regenerate the themes list
148
        $this->container->get('zikula_theme_module.helper.bundle_sync_helper')->regenerate();
149
        // set all themes as active @todo this is probably overkill
150
        $themes = $this->container->get('zikula_theme_module.theme_entity.repository')->findAll();
151
        /** @var \Zikula\ThemeModule\Entity\ThemeEntity $theme */
152
        foreach ($themes as $theme) {
153
            $theme->setState(ThemeEntityRepository::STATE_ACTIVE);
154
        }
155
        $this->container->get('doctrine')->getManager()->flush();
156
157
        return true;
158
    }
159
160
    private function versionUpgrade()
161
    {
162
        /**
163
         * NOTE: There are *intentionally* no `break` statements within each case here so that the process continues
164
         * through each case until the end.
165
         */
166
        switch ($this->currentVersion) {
167
            case '1.4.0':
168
                // perform the following SQL
169
                //ALTER TABLE categories_category ADD CONSTRAINT FK_D0B2B0F88304AF18 FOREIGN KEY (cr_uid) REFERENCES users (uid);
170
                //ALTER TABLE categories_category ADD CONSTRAINT FK_D0B2B0F8C072C1DD FOREIGN KEY (lu_uid) REFERENCES users (uid);
171
                //ALTER TABLE categories_registry ADD CONSTRAINT FK_1B56B4338304AF18 FOREIGN KEY (cr_uid) REFERENCES users (uid);
172
                //ALTER TABLE categories_registry ADD CONSTRAINT FK_1B56B433C072C1DD FOREIGN KEY (lu_uid) REFERENCES users (uid);
173
                //ALTER TABLE sc_intrusion ADD CONSTRAINT FK_8595CE46539B0606 FOREIGN KEY (uid) REFERENCES users (uid);
174
                //DROP INDEX gid_uid ON group_membership;
175
                //ALTER TABLE group_membership DROP PRIMARY KEY;
176
                //ALTER TABLE group_membership ADD CONSTRAINT FK_5132B337539B0606 FOREIGN KEY (uid) REFERENCES users (uid);
177
                //ALTER TABLE group_membership ADD CONSTRAINT FK_5132B3374C397118 FOREIGN KEY (gid) REFERENCES groups (gid);
178
                //CREATE INDEX IDX_5132B337539B0606 ON group_membership (uid);
179
                //CREATE INDEX IDX_5132B3374C397118 ON group_membership (gid);
180
                //ALTER TABLE group_membership ADD PRIMARY KEY (uid, gid);
181
            case '1.4.1':
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...
182
                $request = $this->container->get('request_stack')->getCurrentRequest();
183
                if (isset($request) && $request->hasSession()) {
184
                    $request->getSession()->remove('interactive_init');
185
                    $request->getSession()->remove('interactive_remove');
186
                    $request->getSession()->remove('interactive_upgrade');
187
                }
188
            case '1.4.2':
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...
189
                $this->installModule('ZikulaZAuthModule');
190
                $this->reSyncAndActivateModules();
191
                $this->setModuleCategory('ZikulaZAuthModule', $this->translator->__('Users'));
192
            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...
193
                $this->installModule('ZikulaMenuModule');
194
                $this->reSyncAndActivateModules();
195
                $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
196
            case '1.4.4':
197
                // nothing
198
            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...
199
                // Menu module was introduced in 1.4.4 but not installed on upgrade
200
                $schemaManager = $this->container->get('doctrine')->getConnection()->getSchemaManager();
201
                if (!$schemaManager->tablesExist(['menu_items'])) {
202
                    $this->installModule('ZikulaMenuModule');
203
                    $this->reSyncAndActivateModules();
204
                    $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
205
                }
206
            case '1.4.6':
207
                // nothing needed
208
            case '1.4.7':
209
                // nothing needed
210
        }
211
212
        // always do this
213
        $this->reSyncAndActivateModules();
214
215
        return true;
216
    }
217
218
    private function finalizeParameters()
219
    {
220
        $variableApi = $this->container->get('zikula_extensions_module.api.variable');
221
        // Set the System Identifier as a unique string.
222
        if (!$variableApi->get(VariableApi::CONFIG, 'system_identifier')) {
223
            $variableApi->set(VariableApi::CONFIG, 'system_identifier', str_replace('.', '', uniqid(rand(1000000000, 9999999999), true)));
224
        }
225
226
        // add new configuration parameters
227
        $params = $this->yamlManager->getParameters();
228
        unset($params['username'], $params['password']);
229
        $RandomLibFactory = new Factory();
230
        $generator = $RandomLibFactory->getMediumStrengthGenerator();
231
232
        if (!isset($params['secret']) || ($params['secret'] == 'ThisTokenIsNotSoSecretChangeIt')) {
233
            $params['secret'] = $generator->generateString(50);
234
        }
235
        if (!isset($params['url_secret'])) {
236
            $params['url_secret'] = $generator->generateString(10);
237
        }
238
        // Configure the Request Context
239
        // see http://symfony.com/doc/current/cookbook/console/sending_emails.html#configuring-the-request-context-globally
240
        $request = $this->container->get('request_stack')->getMasterRequest();
241
        $hostFromRequest = isset($request) ? $request->getHost() : null;
242
        $basePathFromRequest = isset($request) ? $request->getBasePath() : null;
243
        $params['router.request_context.host'] = isset($params['router.request_context.host']) ? $params['router.request_context.host'] : $hostFromRequest;
244
        $params['router.request_context.scheme'] = isset($params['router.request_context.scheme']) ? $params['router.request_context.scheme'] : 'http';
245
        $params['router.request_context.base_url'] = isset($params['router.request_context.base_url']) ? $params['router.request_context.base_url'] : $basePathFromRequest;
246
247
        // set currently installed version into parameters
248
        $params[ZikulaKernel::CORE_INSTALLED_VERSION_PARAM] = ZikulaKernel::VERSION;
249
250
        // disable asset combination on upgrades
251
        $params['zikula_asset_manager.combine'] = false;
252
253
        $this->yamlManager->setParameters($params);
254
255
        // store the recent version in a config var for later usage. This enables us to determine the version we are upgrading from
256
        $variableApi->set(VariableApi::CONFIG, 'Version_Num', ZikulaKernel::VERSION);
257
        $variableApi->set(VariableApi::CONFIG, 'Version_Sub', ZikulaKernel::VERSION_SUB);
258
259
        // set the 'start' page information to empty to avoid missing module errors.
260
        $variableApi->set(VariableApi::CONFIG, 'startpage', '');
261
        $variableApi->set(VariableApi::CONFIG, 'starttype', '');
262
        $variableApi->set(VariableApi::CONFIG, 'startfunc', '');
263
        $variableApi->set(VariableApi::CONFIG, 'startargs', '');
264
265
        return true;
266
    }
267
268
    private function clearCaches()
269
    {
270
        // clear cache with zikula's method
271
        $cacheClearer = $this->container->get('zikula.cache_clearer');
272
        $cacheClearer->clear('symfony');
273
        // use full symfony cache_clearer not zikula's to clear entire cache and set for warmup
274
        // console commands always run in `dev` mode but site should be `prod` mode. clear both for good measure.
275
        $this->container->get('cache_clearer')->clear('dev');
276
        $this->container->get('cache_clearer')->clear('prod');
277
        if (in_array($this->container->getParameter('env'), ['dev', 'prod'])) {
278
            // this is just in case anyone ever creates a mode that isn't dev|prod
279
            $this->container->get('cache_clearer')->clear($this->container->getParameter('env'));
280
        }
281
282
        // finally remove upgrading flag in parameters
283
        $this->yamlManager->delParameter('upgrading');
284
285
        return true;
286
    }
287
}
288