Completed
Pull Request — master (#4264)
by Craig
05:17 queued 14s
created

ExtensionInstallerController::preInstallAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 18
rs 9.9
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - 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\ExtensionsModule\Controller;
15
16
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\Routing\Annotation\Route;
20
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
21
use Symfony\Contracts\Translation\TranslatorInterface;
22
use Zikula\Bundle\CoreBundle\Composer\MetaData;
23
use Zikula\Bundle\CoreBundle\Controller\AbstractController;
24
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
25
use Zikula\ExtensionsModule\AbstractExtension;
26
use Zikula\ExtensionsModule\Api\ApiInterface\VariableApiInterface;
27
use Zikula\ExtensionsModule\Constant;
28
use Zikula\ExtensionsModule\Entity\ExtensionEntity;
29
use Zikula\ExtensionsModule\Entity\RepositoryInterface\ExtensionRepositoryInterface;
30
use Zikula\ExtensionsModule\Event\ExtensionPostCacheRebuildEvent;
31
use Zikula\ExtensionsModule\Form\Type\ExtensionInstallType;
32
use Zikula\ExtensionsModule\Helper\ExtensionDependencyHelper;
33
use Zikula\ExtensionsModule\Helper\ExtensionHelper;
34
use Zikula\ExtensionsModule\Helper\ExtensionStateHelper;
35
use Zikula\PermissionsModule\Annotation\PermissionCheck;
36
use Zikula\PermissionsModule\Api\ApiInterface\PermissionApiInterface;
37
use Zikula\ThemeModule\Engine\Annotation\Theme;
38
39
/**
40
 * @Route("")
41
 */
42
class ExtensionInstallerController extends AbstractController
43
{
44
    /**
45
     * @var ExtensionStateHelper
46
     */
47
    private $extensionStateHelper;
48
49
    /**
50
     * @var ExtensionRepositoryInterface
51
     */
52
    private $extensionRepository;
53
54
    /**
55
     * @var ExtensionDependencyHelper
56
     */
57
    private $dependencyHelper;
58
59
    public function __construct(
60
        AbstractExtension $extension,
61
        PermissionApiInterface $permissionApi,
62
        VariableApiInterface $variableApi,
63
        TranslatorInterface $translator,
64
        ExtensionStateHelper $extensionStateHelper,
65
        ExtensionRepositoryInterface $extensionRepository,
66
        ExtensionDependencyHelper $dependencyHelper
67
    ) {
68
        parent::__construct($extension, $permissionApi, $variableApi, $translator);
69
        $this->extensionStateHelper = $extensionStateHelper;
70
        $this->extensionRepository = $extensionRepository;
71
        $this->dependencyHelper = $dependencyHelper;
72
    }
73
74
    /**
75
     * @Route("/preinstall/{id}", requirements={"id" = "^[1-9]\d*$"})
76
     * @PermissionCheck("admin")
77
     * @Theme("admin")
78
     * @Template("@ZikulaExtensionsModule/Extension/preinstall.html.twig")
79
     */
80
    public function preInstallAction(ExtensionEntity $extension)
81
    {
82
        if (Constant::STATE_TRANSITIONAL !== $extension->getState()) {
83
            $this->extensionStateHelper->updateState($extension->getId(), Constant::STATE_TRANSITIONAL);
84
85
            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
86
        }
87
        $unsatisfiedDependencies = $this->dependencyHelper->getUnsatisfiedExtensionDependencies($extension);
88
        $form = $this->createForm(ExtensionInstallType::class, [
89
            'dependencies' => $this->formatDependencyCheckboxArray($unsatisfiedDependencies)
90
        ], [
91
            'action' => $this->generateUrl('zikulaextensionsmodule_extensioninstaller_install', ['id' => $extension->getId()])
92
        ]);
93
94
        return [
95
            'dependencies' => $unsatisfiedDependencies,
96
            'extension' => $extension,
97
            'form' => $form->createView()
98
        ];
99
    }
100
101
    /**
102
     * @Route("/install/{id}", requirements={"id" = "^[1-9]\d*$"})
103
     * @PermissionCheck("admin")
104
     * @Theme("admin")
105
     *
106
     * Install and initialise an extension.
107
     *
108
     * @return RedirectResponse
109
     */
110
    public function installAction(
111
        Request $request,
112
        ExtensionEntity $extension,
113
        ExtensionHelper $extensionHelper
114
    ) {
115
        $id = $extension->getId();
116
117
        $unsatisfiedDependencies = $this->dependencyHelper->getUnsatisfiedExtensionDependencies($extension);
118
        $form = $this->createForm(ExtensionInstallType::class, [
119
            'dependencies' => $this->formatDependencyCheckboxArray($unsatisfiedDependencies)
120
        ]);
121
122
        $form->handleRequest($request);
123
        if ($form->isSubmitted() && $form->isValid()) {
124
            if ($form->get('install')->isClicked()) {
0 ignored issues
show
Bug introduced by
The method isClicked() does not exist on Symfony\Component\Form\FormInterface. It seems like you code against a sub-type of Symfony\Component\Form\FormInterface such as Symfony\Component\Form\SubmitButton. ( Ignorable by Annotation )

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

124
            if ($form->get('install')->/** @scrutinizer ignore-call */ isClicked()) {
Loading history...
125
                $extensionsInstalled = [];
126
                $data = $form->getData();
127
128
                // Install extension dependencies
129
                foreach ($data['dependencies'] as $dependencyId => $installSelected) {
130
                    if (!$installSelected && MetaData::DEPENDENCY_REQUIRED !== $unsatisfiedDependencies[$dependencyId]->getStatus()) {
131
                        continue;
132
                    }
133
                    $dependencyExtensionEntity = $this->extensionRepository->get($unsatisfiedDependencies[$dependencyId]->getModname());
134
                    if (isset($dependencyExtensionEntity)) {
135
                        if (!$extensionHelper->install($dependencyExtensionEntity)) {
136
                            $this->addFlash('error', $this->trans('Failed to install dependency "%name%"!', ['%name%' => $dependencyExtensionEntity->getName()]));
137
138
                            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
139
                        }
140
                        $extensionsInstalled[] = $dependencyExtensionEntity->getId();
141
                        $this->addFlash('status', $this->trans('Installed dependency "%name%".', ['%name%' => $dependencyExtensionEntity->getName()]));
142
                    } else {
143
                        $this->addFlash('warning', $this->trans('Warning: could not install selected dependency "%name%".', ['%name%' => $unsatisfiedDependencies[$dependencyId]->getModname()]));
144
                    }
145
                }
146
147
                if ($extensionHelper->install($extension)) {
148
                    $this->addFlash('status', $this->trans('Done! Installed "%name%".', ['%name%' => $extension->getName()]));
149
                    $extensionsInstalled[] = $id;
150
151
                    return $this->redirectToRoute('zikulaextensionsmodule_extensioninstaller_postinstall', ['extensions' => json_encode($extensionsInstalled)]);
152
                }
153
                $this->extensionStateHelper->updateState($id, Constant::STATE_UNINITIALISED);
154
                $this->addFlash('error', $this->trans('Initialization of "%name%" failed!', ['%name%' => $extension->getName()]));
155
            }
156
            if ($form->get('cancel')->isClicked()) {
157
                $this->extensionStateHelper->updateState($id, Constant::STATE_UNINITIALISED);
158
                $this->addFlash('status', 'Operation cancelled.');
159
            }
160
        }
161
162
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
163
    }
164
165
    /**
166
     * Post-installation action to trigger the MODULE_POSTINSTALL event.
167
     * The additional Action is required because this event must occur AFTER the rebuild of the cache which occurs on Request.
168
     *
169
     * @Route("/postinstall/{extensions}", methods = {"GET"})
170
     */
171
    public function postInstallAction(
172
        ZikulaHttpKernelInterface $kernel,
173
        EventDispatcherInterface $eventDispatcher,
174
        string $extensions = null
175
    ): RedirectResponse {
176
        if (!empty($extensions)) {
177
            $extensions = json_decode($extensions);
178
            foreach ($extensions as $extensionId) {
179
                /** @var ExtensionEntity $extensionEntity */
180
                $extensionEntity = $this->extensionRepository->find($extensionId);
181
                if (null === $this->extensionRepository) {
182
                    continue;
183
                }
184
                /** @var AbstractExtension $extensionBundle */
185
                $extensionBundle = $kernel->getBundle($extensionEntity->getName());
186
                $eventDispatcher->dispatch(new ExtensionPostCacheRebuildEvent($extensionBundle, $extensionEntity));
187
            }
188
        }
189
190
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list', ['justinstalled' => json_encode($extensions)]);
191
    }
192
193
    /**
194
     * Create array suitable for checkbox FormType [[ID => bool][ID => bool]].
195
     */
196
    private function formatDependencyCheckboxArray(array $dependencies): array
197
    {
198
        $return = [];
199
        foreach ($dependencies as $dependency) {
200
            /** @var ExtensionEntity $dependencyExtension */
201
            $dependencyExtension = $this->extensionRepository->get($dependency->getModname());
202
            $return[$dependency->getId()] = null !== $dependencyExtension;
203
        }
204
205
        return $return;
206
    }
207
}
208