Completed
Push — master ( 89c3e8...c161b3 )
by Craig
05:56 queued 40s
created

CoreInstallerExtensionHelper::install()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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