1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file is part of the Zikula package. |
7
|
|
|
* |
8
|
|
|
* Copyright Zikula Foundation - 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\BlocksModule; |
15
|
|
|
|
16
|
|
|
use Exception; |
17
|
|
|
use Doctrine\Persistence\ManagerRegistry; |
18
|
|
|
use Symfony\Component\HttpFoundation\RequestStack; |
19
|
|
|
use Symfony\Contracts\Translation\TranslatorInterface; |
20
|
|
|
use Zikula\BlocksModule\Block\HtmlBlock; |
21
|
|
|
use Zikula\BlocksModule\Entity\BlockEntity; |
22
|
|
|
use Zikula\BlocksModule\Entity\BlockPlacementEntity; |
23
|
|
|
use Zikula\BlocksModule\Entity\BlockPositionEntity; |
24
|
|
|
use Zikula\BlocksModule\Helper\InstallerHelper; |
25
|
|
|
use Zikula\Bundle\CoreBundle\Doctrine\Helper\SchemaHelper; |
26
|
|
|
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface; |
27
|
|
|
use Zikula\ExtensionsModule\AbstractExtension; |
28
|
|
|
use Zikula\ExtensionsModule\Api\ApiInterface\VariableApiInterface; |
29
|
|
|
use Zikula\ExtensionsModule\Entity\ExtensionEntity; |
30
|
|
|
use Zikula\ExtensionsModule\Installer\AbstractExtensionInstaller; |
31
|
|
|
use Zikula\SearchModule\Block\SearchBlock; |
32
|
|
|
use Zikula\UsersModule\Block\LoginBlock; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Installation and upgrade routines for the blocks module. |
36
|
|
|
*/ |
37
|
|
|
class BlocksModuleInstaller extends AbstractExtensionInstaller |
38
|
|
|
{ |
39
|
|
|
/** |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
private $entities = [ |
43
|
|
|
BlockEntity::class, |
44
|
|
|
BlockPositionEntity::class, |
45
|
|
|
BlockPlacementEntity::class |
46
|
|
|
]; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var ZikulaHttpKernelInterface |
50
|
|
|
*/ |
51
|
|
|
private $kernel; |
52
|
|
|
|
53
|
|
|
public function __construct( |
54
|
|
|
ZikulaHttpKernelInterface $kernel, |
55
|
|
|
AbstractExtension $extension, |
56
|
|
|
ManagerRegistry $managerRegistry, |
57
|
|
|
SchemaHelper $schemaTool, |
58
|
|
|
RequestStack $requestStack, |
59
|
|
|
TranslatorInterface $translator, |
60
|
|
|
VariableApiInterface $variableApi |
61
|
|
|
) { |
62
|
|
|
$this->kernel = $kernel; |
63
|
|
|
parent::__construct($extension, $managerRegistry, $schemaTool, $requestStack, $translator, $variableApi); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
public function install(): bool |
67
|
|
|
{ |
68
|
|
|
try { |
69
|
|
|
$this->schemaTool->create($this->entities); |
70
|
|
|
} catch (Exception $exception) { |
71
|
|
|
return false; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
// Set a default value for a module variable |
75
|
|
|
$this->setVar('collapseable', false); |
76
|
|
|
|
77
|
|
|
// Initialisation successful |
78
|
|
|
return true; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
public function upgrade(string $oldVersion): bool |
82
|
|
|
{ |
83
|
|
|
$blockRepository = $this->entityManager->getRepository(BlockEntity::class); |
84
|
|
|
// Upgrade dependent on old version number |
85
|
|
|
switch ($oldVersion) { |
86
|
|
|
case '3.8.1': |
87
|
|
|
case '3.8.2': |
88
|
|
|
case '3.9.0': |
89
|
|
|
$sql = 'SELECT * FROM blocks'; |
90
|
|
|
$blocks = $this->entityManager->getConnection()->fetchAll($sql); |
|
|
|
|
91
|
|
|
foreach ($blocks as $block) { |
92
|
|
|
$content = $block['content']; |
93
|
|
|
if ($this->isSerialized($content)) { |
94
|
|
|
$content = unserialize($content); |
95
|
|
|
foreach ($content as $k => $item) { |
96
|
|
|
if (is_string($item)) { |
97
|
|
|
if (false !== mb_strpos($item, 'blocks_block_extmenu_topnav.tpl')) { |
98
|
|
|
$content[$k] = str_replace('blocks_block_extmenu_topnav.tpl', 'Block/Extmenu/topnav.tpl', $item); |
99
|
|
|
} elseif (false !== mb_strpos($item, 'blocks_block_extmenu.tpl')) { |
100
|
|
|
$content[$k] = str_replace('blocks_block_extmenu.tpl', 'Block/Extmenu/extmenu.tpl', $item); |
101
|
|
|
} elseif (false !== mb_strpos($item, 'menutree/blocks_block_menutree_')) { |
102
|
|
|
$content[$k] = str_replace('menutree/blocks_block_menutree_', 'Block/Menutree/', $item); |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
$this->entityManager->getConnection()->executeUpdate('UPDATE blocks SET content=? WHERE bid=?', [serialize($content), $block['bid']]); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// check if request is available (#2073) |
111
|
|
|
$templateWarning = $this->trans('Warning: Block template locations modified, you may need to fix your template overrides if you have any.'); |
112
|
|
|
$request = $this->requestStack->getMasterRequest(); |
113
|
|
|
if ( |
114
|
|
|
is_object($request) |
115
|
|
|
&& method_exists($request, 'getSession') |
116
|
|
|
&& is_object($request->getSession()) |
117
|
|
|
) { |
118
|
|
|
$this->addFlash('warning', $templateWarning); |
119
|
|
|
} |
120
|
|
|
case '3.9.1': |
121
|
|
|
// make all content fields of blocks serialized. |
122
|
|
|
$sql = 'SELECT * FROM blocks'; |
123
|
|
|
$blocks = $this->entityManager->getConnection()->fetchAll($sql); |
124
|
|
|
$oldContent = []; |
125
|
|
|
foreach ($blocks as $block) { |
126
|
|
|
$block['content'] = !empty($block['content']) ? $block['content'] : ''; |
127
|
|
|
$oldContent[$block['bid']] = $this->isSerialized($block['content']) ? unserialize($block['content']) : ['content' => $block['content']]; |
128
|
|
|
} |
129
|
|
|
$this->schemaTool->update($this->entities); |
130
|
|
|
$this->entityManager->getConnection()->executeQuery("UPDATE blocks SET properties='a:0:{}'"); |
131
|
|
|
|
132
|
|
|
$blocks = $blockRepository->findAll(); |
133
|
|
|
$installerHelper = new InstallerHelper(); |
134
|
|
|
/** @var ZikulaHttpKernelInterface $kernel */ |
135
|
|
|
/** @var BlockEntity $block */ |
136
|
|
|
foreach ($blocks as $block) { |
137
|
|
|
$block->setProperties($oldContent[$block->getBid()]); |
138
|
|
|
$block->setFilters($installerHelper->upgradeFilterArray($block->getFilters())); |
139
|
|
|
$block->setBlocktype(preg_match('/Block$/', $block->getBkey()) ? mb_substr($block->getBkey(), 0, -5) : $block->getBkey()); |
140
|
|
|
$block->setBkey($installerHelper->upgradeBkeyToFqClassname($this->kernel, $block)); |
141
|
|
|
} |
142
|
|
|
$this->entityManager->flush(); |
143
|
|
|
|
144
|
|
|
$collapseable = $this->getVar('collapseable'); |
145
|
|
|
$this->setVar('collapseable', (bool)$collapseable); |
146
|
|
|
|
147
|
|
|
case '3.9.2': |
148
|
|
|
// convert Text and Html block types so properties is proper array |
149
|
|
|
$blocks = $blockRepository->findBy(['blocktype' => ['Html', 'Text']]); |
150
|
|
|
foreach ($blocks as $block) { |
151
|
|
|
$properties = $block->getProperties(); |
152
|
|
|
if (!is_array($properties)) { |
153
|
|
|
$block->setProperties(['content' => $properties]); |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
$this->entityManager->flush(); |
157
|
|
|
case '3.9.3': |
158
|
|
|
$this->schemaTool->drop([ |
|
|
|
|
159
|
|
|
'Zikula\BlocksModule\Entity\UserBlockEntity' |
160
|
|
|
]); |
161
|
|
|
case '3.9.4': |
162
|
|
|
// convert integer values to boolean for search block settings |
163
|
|
|
$searchBlocks = $blockRepository->findBy(['blocktype' => 'Search']); |
164
|
|
|
foreach ($searchBlocks as $searchBlock) { |
165
|
|
|
$properties = $searchBlock->getProperties(); |
166
|
|
|
$properties['displaySearchBtn'] = (bool)$properties['displaySearchBtn']; |
167
|
|
|
if (isset($properties['active'])) { |
168
|
|
|
foreach ($properties['active'] as $module => $active) { |
169
|
|
|
$properties['active'][$module] = (bool)$active; |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
$searchBlock->setProperties($properties); |
173
|
|
|
} |
174
|
|
|
$this->entityManager->flush(); |
175
|
|
|
case '3.9.5': |
176
|
|
|
$loginBlocks = $blockRepository->findBy(['blocktype' => 'Login']); |
177
|
|
|
foreach ($loginBlocks as $loginBlock) { |
178
|
|
|
$filters = $loginBlock->getFilters(); |
179
|
|
|
$filters[] = [ |
180
|
|
|
'attribute' => '_route', |
181
|
|
|
'queryParameter' => null, |
182
|
|
|
'comparator' => '!=', |
183
|
|
|
'value' => 'zikulausersmodule_access_login' |
184
|
|
|
]; |
185
|
|
|
$loginBlock->setFilters($filters); |
186
|
|
|
} |
187
|
|
|
$this->entityManager->flush(); |
|
|
|
|
188
|
|
|
case '3.9.6': |
189
|
|
|
$statement = $this->entityManager->getConnection()->executeQuery("SELECT * FROM blocks WHERE blocktype = 'Lang'"); |
190
|
|
|
$blocks = $statement->fetchAll(\PDO::FETCH_ASSOC); |
191
|
|
|
if (count($blocks) > 0) { |
192
|
|
|
$this->entityManager->getConnection()->executeQuery("UPDATE blocks set bkey=?, blocktype=?, properties=? WHERE blocktype = 'Lang'", [ |
193
|
|
|
'ZikulaSettingsModule:Zikula\SettingsModule\Block\LocaleBlock', |
194
|
|
|
'Locale', |
195
|
|
|
'a:0:{}' |
196
|
|
|
]); |
197
|
|
|
$this->addFlash('success', 'All instances of LangBlock have been converted to LocaleBlock.'); |
198
|
|
|
} |
199
|
|
|
$this->entityManager->getConnection()->executeQuery("UPDATE group_perms SET component = REPLACE(component, 'Languageblock', 'LocaleBlock') WHERE component LIKE 'Languageblock%'"); |
200
|
|
|
case '3.9.7': |
201
|
|
|
case '3.9.8': |
202
|
|
|
$statement = $this->entityManager->getConnection()->executeQuery("SELECT * FROM blocks"); |
203
|
|
|
$blocks = $statement->fetchAll(\PDO::FETCH_ASSOC); |
204
|
|
|
foreach ($blocks as $block) { |
205
|
|
|
$bKey = $block['bkey']; |
206
|
|
|
if (mb_strpos($bKey, ':')) { |
207
|
|
|
[/*$moduleName*/, $bKey] = explode(':', $bKey); |
208
|
|
|
} |
209
|
|
|
$this->entityManager->getConnection()->executeUpdate('UPDATE blocks SET bKey=? WHERE bid=?', [trim($bKey, '\\'), $block['bid']]); |
210
|
|
|
} |
211
|
|
|
case '3.9.9': |
212
|
|
|
// future upgrade routines |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
// Update successful |
216
|
|
|
return true; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
public function uninstall(): bool |
220
|
|
|
{ |
221
|
|
|
// Deletion not allowed |
222
|
|
|
return false; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Add default block data for new installations. |
227
|
|
|
* This is called after a complete installation since the blocks |
228
|
|
|
* need to be populated with module id's which are only available |
229
|
|
|
* once the installation has been completed. |
230
|
|
|
*/ |
231
|
|
|
public function createDefaultData(): void |
232
|
|
|
{ |
233
|
|
|
// create the default block positions - left, right and center for the traditional 3 column layout |
234
|
|
|
$positions = [ |
235
|
|
|
'left' => $this->trans('Left blocks'), |
236
|
|
|
'right' => $this->trans('Right blocks'), |
237
|
|
|
'center' => $this->trans('Center blocks'), |
238
|
|
|
'search' => $this->trans('Search block'), |
239
|
|
|
'header' => $this->trans('Header block'), |
240
|
|
|
'footer' => $this->trans('Footer block'), |
241
|
|
|
'topnav' => $this->trans('Top navigation block'), |
242
|
|
|
'bottomnav' => $this->trans('Bottom navigation block') |
243
|
|
|
]; |
244
|
|
|
foreach ($positions as $name => $description) { |
245
|
|
|
$positions[$name] = new BlockPositionEntity(); |
246
|
|
|
$positions[$name]->setName($name); |
247
|
|
|
$positions[$name]->setDescription($description); |
248
|
|
|
$this->entityManager->persist($positions[$name]); |
|
|
|
|
249
|
|
|
} |
250
|
|
|
$this->entityManager->flush(); |
251
|
|
|
|
252
|
|
|
$hellomessage = $this->trans('<p><a href="https://ziku.la">Zikula</a> is an Open Source Content Application Framework built on top of Symfony.</p><p>With Zikula you get:</p><ul><li><strong>Power:</strong> You get the all the features of <a href="https://symfony.com">Symfony</a> PLUS: </li><li><strong>User Management:</strong> Built in User and Group management with Rights/Roles control</li><li><strong>Front end control:</strong> You can customise all aspects of the site\'s appearance through themes, with support for <a href="http://jquery.com">jQuery</a>, <a href="http://getbootstrap.com">Bootstrap</a> and many other modern technologies</li><li><strong>Internationalization (i18n):</strong> You can mark content as being suitable for either a single language or for all languages, and can control all aspects of localisation of your site</li><li><strong>Extensibility:</strong> you get a standard application-programming interface (API) that lets you easily extend your site\'s functionality through modules</li><li><strong>More:</strong> Admin UI, global categories, site-wide search, content blocks, menu creation, and more!</li><li><strong>Support:</strong> you can get help and support from the Zikula community of webmasters and developers at <a href="https://ziku.la">ziku.la</a>, <a href="https://github.com/zikula/core">Github</a> and <a href="https://zikula.slack.com/">Slack</a>.</li></ul><p>Enjoy using Zikula!</p><p><strong>The Zikula team</strong></p><p><em>Note: Zikula is Free Open Source Software (FOSS) licensed under the GNU General Public License.</em></p>'); |
253
|
|
|
|
254
|
|
|
$blocks = []; |
255
|
|
|
$extensionRepo = $this->entityManager->getRepository(ExtensionEntity::class); |
256
|
|
|
$blocksModuleEntity = $extensionRepo->findOneBy(['name' => 'ZikulaBlocksModule']); |
257
|
|
|
$searchModuleEntity = $extensionRepo->findOneBy(['name' => 'ZikulaSearchModule']); |
258
|
|
|
$usersModuleEntity = $extensionRepo->findOneBy(['name' => 'ZikulaUsersModule']); |
259
|
|
|
$blocks[] = [ |
260
|
|
|
'bkey' => SearchBlock::class, |
261
|
|
|
'blocktype' => 'Search', |
262
|
|
|
'language' => '', |
263
|
|
|
'module' => $searchModuleEntity, |
264
|
|
|
'title' => $this->trans('Search box'), |
265
|
|
|
'description' => $this->trans('Search block'), |
266
|
|
|
'properties' => [ |
267
|
|
|
'displaySearchBtn' => true, |
268
|
|
|
'active' => ['ZikulaUsersModule' => 1] |
269
|
|
|
], |
270
|
|
|
'position' => $positions['left'] |
271
|
|
|
]; |
272
|
|
|
$blocks[] = [ |
273
|
|
|
'bkey' => HtmlBlock::class, |
274
|
|
|
'blocktype' => 'Html', |
275
|
|
|
'language' => '', |
276
|
|
|
'module' => $blocksModuleEntity, |
277
|
|
|
'title' => $this->trans('This site is powered by Zikula!'), |
278
|
|
|
'description' => $this->trans('HTML block'), |
279
|
|
|
'properties' => ['content' => $hellomessage], |
280
|
|
|
'position' => $positions['center'] |
281
|
|
|
]; |
282
|
|
|
$blocks[] = [ |
283
|
|
|
'bkey' => LoginBlock::class, |
284
|
|
|
'blocktype' => 'Login', |
285
|
|
|
'language' => '', |
286
|
|
|
'module' => $usersModuleEntity, |
287
|
|
|
'title' => $this->trans('User log-in'), |
288
|
|
|
'description' => $this->trans('Login block'), |
289
|
|
|
'position' => $positions['topnav'], |
290
|
|
|
'order' => 1, |
291
|
|
|
'filters' => [[ |
292
|
|
|
'attribute' => '_route', |
293
|
|
|
'queryParameter' => null, |
294
|
|
|
'comparator' => '!=', |
295
|
|
|
'value' => 'zikulausersmodule_access_login' |
296
|
|
|
]] |
297
|
|
|
]; |
298
|
|
|
|
299
|
|
|
foreach ($blocks as $block) { |
300
|
|
|
$blockEntity = new BlockEntity(); |
301
|
|
|
$position = $block['position']; |
302
|
|
|
$sortOrder = !empty($block['order']) ? $block['order'] : 0; |
303
|
|
|
unset($block['position'], $block['order']); |
304
|
|
|
$blockEntity->merge($block); |
305
|
|
|
$this->entityManager->persist($blockEntity); |
306
|
|
|
$placement = new BlockPlacementEntity(); |
307
|
|
|
$placement->setBlock($blockEntity); |
308
|
|
|
$placement->setPosition($position); |
309
|
|
|
$placement->setSortorder($sortOrder); |
310
|
|
|
$this->entityManager->persist($placement); |
311
|
|
|
} |
312
|
|
|
$this->entityManager->flush(); |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
private function isSerialized($string): bool |
316
|
|
|
{ |
317
|
|
|
// temporarily suppress E_NOTICE to avoid using @unserialize |
318
|
|
|
$errorReporting = error_reporting(error_reporting() ^ E_NOTICE); |
319
|
|
|
|
320
|
|
|
$result = 'b:0;' === $string || false !== unserialize($string); |
321
|
|
|
|
322
|
|
|
error_reporting($errorReporting); |
323
|
|
|
|
324
|
|
|
return $result; |
325
|
|
|
} |
326
|
|
|
} |
327
|
|
|
|