|
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": |
|
|
|
|
|
|
79
|
|
|
$params = $this->decodeParameters($this->yamlManager->getParameters()); |
|
80
|
|
|
|
|
81
|
|
|
return $this->loginAdmin($params); |
|
82
|
|
|
case "upgrade_event": |
|
|
|
|
|
|
83
|
|
|
return $this->fireEvent(CoreEvents::CORE_UPGRADE_PRE_MODULE, ['currentVersion' => $this->currentVersion]); |
|
84
|
|
|
case "upgrademodules": |
|
|
|
|
|
|
85
|
|
|
$result = $this->upgradeModules(); |
|
86
|
|
|
if (count($result) === 0) { |
|
87
|
|
|
return true; |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
return $result; |
|
91
|
|
|
case "regenthemes": |
|
|
|
|
|
|
92
|
|
|
return $this->regenerateThemes(); |
|
93
|
|
|
case "versionupgrade": |
|
|
|
|
|
|
94
|
|
|
return $this->versionUpgrade(); |
|
95
|
|
|
case "finalizeparameters": |
|
|
|
|
|
|
96
|
|
|
return $this->finalizeParameters(); |
|
97
|
|
|
case "clearcaches": |
|
|
|
|
|
|
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 |
|
|
|
|
|
|
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': |
|
|
|
|
|
|
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': |
|
|
|
|
|
|
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;"; |
|
|
|
|
|
|
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'); |
|
|
|
|
|
|
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']); |
|
|
|
|
|
|
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
|
|
|
|
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.
will print an indented:
Single is ValueIf 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.