Completed
Push — master ( e8ce57...2ef872 )
by Craig
10:53 queued 04:32
created

BlocksModuleInstaller::upgrade()   F

Complexity

Conditions 37
Paths 4032

Size

Total Lines 136
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
cc 37
eloc 98
c 3
b 2
f 0
nc 4032
nop 1
dl 0
loc 136
rs 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
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);
0 ignored issues
show
Bug introduced by
The method getConnection() does not exist on Doctrine\Persistence\ObjectManager. It seems like you code against a sub-type of Doctrine\Persistence\ObjectManager such as Doctrine\ORM\Decorator\EntityManagerDecorator or Doctrine\ORM\EntityManagerInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
                $blocks = $this->entityManager->/** @scrutinizer ignore-call */ getConnection()->fetchAll($sql);
Loading history...
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([
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
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();
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
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]);
0 ignored issues
show
Bug introduced by
$positions[$name] of type string is incompatible with the type object expected by parameter $object of Doctrine\Persistence\ObjectManager::persist(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

248
            $this->entityManager->persist(/** @scrutinizer ignore-type */ $positions[$name]);
Loading history...
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