Passed
Push — master ( 8a455a...42a228 )
by Craig
07:01
created

ModuleHelper::categorizeModules()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 20
nc 2
nop 0
dl 0
loc 26
rs 9.6
c 0
b 0
f 0
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\Bundle\CoreInstallerBundle\Helper;
15
16
use ReflectionClass;
17
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Zikula\BlocksModule\Entity\BlockEntity;
20
use Zikula\Bundle\CoreBundle\Bundle\AbstractCoreModule;
21
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
22
use Zikula\Bundle\CoreBundle\YamlDumper;
23
use Zikula\Common\Translator\Translator;
24
use Zikula\Common\Translator\TranslatorInterface;
25
use Zikula\ExtensionsModule\Api\VariableApi;
26
use Zikula\ExtensionsModule\Constant;
27
use Zikula\ExtensionsModule\Entity\ExtensionEntity;
28
use Zikula\ExtensionsModule\Helper\BundleSyncHelper;
29
use Zikula\ExtensionsModule\Helper\ExtensionHelper;
30
31
class ModuleHelper
32
{
33
    /**
34
     * @var ContainerInterface
35
     */
36
    private $container;
37
38
    /**
39
     * @var TranslatorInterface
40
     */
41
    private $translator;
42
43
    /**
44
     * @var YamlDumper
45
     */
46
    private $yamlHelper;
47
48
    public function __construct(
49
        ContainerInterface $container
50
    ) {
51
        $this->container = $container;
52
        $this->translator = $container->get(Translator::class);
53
        $this->yamlHelper = $container->get(ParameterHelper::class)->getYamlHelper();
54
    }
55
56
    public function installModule(string $moduleName): bool
57
    {
58
        $module = $this->container->get('kernel')->getModule($moduleName);
59
        /** @var AbstractCoreModule $module */
60
        $className = $module->getInstallerClass();
61
        $reflectionInstaller = new ReflectionClass($className);
62
        $installer = $reflectionInstaller->newInstance();
63
        $installer->setBundle($module);
64
        if ($installer instanceof ContainerAwareInterface) {
65
            $installer->setContainer($this->container);
66
        }
67
68
        if ($installer->install()) {
69
            return true;
70
        }
71
72
        return false;
73
    }
74
75
    /**
76
     * Set an admin category for a module or set to default.
77
     */
78
    private function setModuleCategory(string $moduleName, string $translatedCategoryName): bool
79
    {
80
        $doctrine = $this->container->get('doctrine');
81
        $categoryRepository = $doctrine->getRepository('ZikulaAdminModule:AdminCategoryEntity');
82
        $modulesCategories = $categoryRepository->getIndexedCollection('name');
83
        $moduleEntity = $doctrine->getRepository('ZikulaExtensionsModule:ExtensionEntity')
84
            ->findOneBy(['name' => $moduleName]);
85
86
        $moduleRepository = $doctrine->getRepository('ZikulaAdminModule:AdminModuleEntity');
87
        if (isset($modulesCategories[$translatedCategoryName])) {
88
            $moduleRepository->setModuleCategory($moduleEntity, $modulesCategories[$translatedCategoryName]);
89
        } else {
90
            $defaultCategoryId = $this->container->get(VariableApi::class)->get('ZikulaAdminModule', 'defaultcategory', 5);
91
            $defaultCategory = $categoryRepository->find($defaultCategoryId);
92
            $moduleRepository->setModuleCategory($moduleEntity, $defaultCategory);
93
        }
94
95
        return true;
96
    }
97
98
    public function categorizeModules(): bool
99
    {
100
        reset(ZikulaKernel::$coreModules);
101
        $systemModulesCategories = [
102
            'ZikulaExtensionsModule' => $this->translator->__('System'),
103
            'ZikulaPermissionsModule' => $this->translator->__('Users'),
104
            'ZikulaGroupsModule' => $this->translator->__('Users'),
105
            'ZikulaBlocksModule' => $this->translator->__('Layout'),
106
            'ZikulaUsersModule' => $this->translator->__('Users'),
107
            'ZikulaZAuthModule' => $this->translator->__('Users'),
108
            'ZikulaThemeModule' => $this->translator->__('Layout'),
109
            'ZikulaSecurityCenterModule' => $this->translator->__('Security'),
110
            'ZikulaCategoriesModule' => $this->translator->__('Content'),
111
            'ZikulaMailerModule' => $this->translator->__('System'),
112
            'ZikulaSearchModule' => $this->translator->__('Content'),
113
            'ZikulaAdminModule' => $this->translator->__('System'),
114
            'ZikulaSettingsModule' => $this->translator->__('System'),
115
            'ZikulaRoutesModule' => $this->translator->__('System'),
116
            'ZikulaMenuModule' => $this->translator->__('Content'),
117
        ];
118
119
        foreach (ZikulaKernel::$coreModules as $systemModule => $bundleClass) {
120
            $this->setModuleCategory($systemModule, $systemModulesCategories[$systemModule]);
121
        }
122
123
        return true;
124
    }
125
126
    /**
127
     * Scan the filesystem and sync the modules table. Set all core modules to active state.
128
     */
129
    public function reSyncAndActivateModules(): bool
130
    {
131
        $bundleSyncHelper = $this->container->get(BundleSyncHelper::class);
132
        $extensionsInFileSystem = $bundleSyncHelper->scanForBundles();
133
        $bundleSyncHelper->syncExtensions($extensionsInFileSystem);
134
135
        $doctrine = $this->container->get('doctrine');
136
137
        /** @var ExtensionEntity[] $extensions */
138
        $extensions = $doctrine->getRepository('ZikulaExtensionsModule:ExtensionEntity')
139
            ->findBy(['name' => array_keys(ZikulaKernel::$coreModules)]);
140
        foreach ($extensions as $extension) {
141
            $extension->setState(Constant::STATE_ACTIVE);
142
        }
143
        $doctrine->getManager()->flush();
144
145
        return true;
146
    }
147
148
    /**
149
     * Attempt to upgrade ALL the core modules. Some will need it, some will not.
150
     * Modules that do not need upgrading return TRUE as a result of the upgrade anyway.
151
     */
152
    public function upgradeModules(): bool
153
    {
154
        $coreModulesInPriorityUpgradeOrder = [
155
            'ZikulaExtensionsModule',
156
            'ZikulaUsersModule',
157
            'ZikulaZAuthModule',
158
            'ZikulaGroupsModule',
159
            'ZikulaPermissionsModule',
160
            'ZikulaAdminModule',
161
            'ZikulaBlocksModule',
162
            'ZikulaThemeModule',
163
            'ZikulaSettingsModule',
164
            'ZikulaCategoriesModule',
165
            'ZikulaSecurityCenterModule',
166
            'ZikulaRoutesModule',
167
            'ZikulaMailerModule',
168
            'ZikulaSearchModule',
169
            'ZikulaMenuModule',
170
        ];
171
        $result = true;
172
        foreach ($coreModulesInPriorityUpgradeOrder as $moduleName) {
173
            $extensionEntity = $this->container->get('doctrine')->getRepository('ZikulaExtensionsModule:ExtensionEntity')->get($moduleName);
174
            if (isset($extensionEntity)) {
175
                $result = $result && $this->container->get(ExtensionHelper::class)->upgrade($extensionEntity);
176
            }
177
        }
178
179
        return $result;
180
    }
181
182
    public function executeCoreMetaUpgrade($currentCoreVersion): bool
183
    {
184
        $doctrine = $this->container->get('doctrine');
185
        /**
186
         * NOTE: There are *intentionally* no `break` statements within each case here so that the process continues
187
         * through each case until the end.
188
         */
189
        switch ($currentCoreVersion) {
190
            case '1.4.3':
191
                $this->installModule('ZikulaMenuModule');
192
                $this->reSyncAndActivateModules();
193
                $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
194
            case '1.4.4':
195
                // nothing
196
            case '1.4.5':
197
                // Menu module was introduced in 1.4.4 but not installed on upgrade
198
                $schemaManager = $doctrine->getConnection()->getSchemaManager();
199
                if (!$schemaManager->tablesExist(['menu_items'])) {
200
                    $this->installModule('ZikulaMenuModule');
201
                    $this->reSyncAndActivateModules();
202
                    $this->setModuleCategory('ZikulaMenuModule', $this->translator->__('Content'));
203
                }
204
            case '1.4.6':
205
                // nothing needed
206
            case '1.4.7':
207
                // nothing needed
208
            case '1.5.0':
209
                // nothing needed
210
            case '1.9.99':
211
                // upgrades required for 2.0.0
212
                foreach (['objectdata_attributes', 'objectdata_log', 'objectdata_meta', 'workflows'] as $table) {
213
                    $sql = "DROP TABLE ${table};";
214
                    /** @var \Doctrine\DBAL\Driver\PDOConnection $connection */
215
                    $connection = $doctrine->getConnection();
216
                    $stmt = $connection->prepare($sql);
217
                    $stmt->execute();
218
                    $stmt->closeCursor();
219
                }
220
                $variableApi = $this->container->get(VariableApi::class);
221
                $variableApi->del(VariableApi::CONFIG, 'metakeywords');
222
                $variableApi->del(VariableApi::CONFIG, 'startpage');
223
                $variableApi->del(VariableApi::CONFIG, 'startfunc');
224
                $variableApi->del(VariableApi::CONFIG, 'starttype');
225
                if ('userdata' === $this->container->getParameter('datadir')) {
226
                    $this->yamlHelper->setParameter('datadir', 'web/uploads');
227
                    $fs = $this->container->get('filesystem');
228
                    $src = dirname(__DIR__, 5) . '/';
229
                    try {
230
                        if ($fs->exists($src . '/userdata')) {
231
                            $fs->mirror($src . '/userdata', $src . '/web/uploads');
232
                        }
233
                    } catch (\Exception $exception) {
234
                        $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.'));
235
                    }
236
                }
237
                // remove legacy blocks
238
                $blocksToRemove = $doctrine->getRepository(BlockEntity::class)->findBy(['blocktype' => ['Extmenu', 'Menutree', 'Menu']]);
239
                foreach ($blocksToRemove as $block) {
240
                    $doctrine->getManager()->remove($block);
241
                }
242
                $doctrine->getManager()->flush();
243
            case '2.0.0':
244
                // nothing needed
245
            case '3.0.0':
246
                // current version - cannot perform anything yet
247
        }
248
249
        // always do this
250
        $this->reSyncAndActivateModules();
251
252
        return true;
253
    }
254
}
255