Completed
Push — master ( caeb59...e7b0db )
by Axel
05:20
created

ExtensionInstallerController::postInstall()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 2
nop 3
dl 0
loc 20
rs 9.9666
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 - 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 preInstall(ExtensionEntity $extension)
81
    {
82
        if (Constant::STATE_TRANSITIONAL !== $extension->getState()) {
83
            $this->extensionStateHelper->updateState($extension->getId(), Constant::STATE_TRANSITIONAL);
84
            $this->addFlash('success', $this->renderView('@ZikulaExtensionsModule/Extension/installReadyFlashMessage.html.twig', ['extension' => $extension]));
85
86
            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
87
        }
88
        $unsatisfiedDependencies = $this->dependencyHelper->getUnsatisfiedExtensionDependencies($extension);
89
        $form = $this->createForm(ExtensionInstallType::class, [
90
            'dependencies' => $this->formatDependencyCheckboxArray($unsatisfiedDependencies)
91
        ], [
92
            'action' => $this->generateUrl('zikulaextensionsmodule_extensioninstaller_install', ['id' => $extension->getId()])
93
        ]);
94
95
        return [
96
            'dependencies' => $unsatisfiedDependencies,
97
            'extension' => $extension,
98
            'form' => $form->createView()
99
        ];
100
    }
101
102
    /**
103
     * @Route("/install/{id}", requirements={"id" = "^[1-9]\d*$"})
104
     * @PermissionCheck("admin")
105
     * @Theme("admin")
106
     *
107
     * Install and initialise an extension.
108
     *
109
     * @return RedirectResponse
110
     */
111
    public function install(
112
        Request $request,
113
        ExtensionEntity $extension,
114
        ExtensionHelper $extensionHelper
115
    ) {
116
        $id = $extension->getId();
117
118
        $unsatisfiedDependencies = $this->dependencyHelper->getUnsatisfiedExtensionDependencies($extension);
119
        $form = $this->createForm(ExtensionInstallType::class, [
120
            'dependencies' => $this->formatDependencyCheckboxArray($unsatisfiedDependencies)
121
        ]);
122
123
        $form->handleRequest($request);
124
        if ($form->isSubmitted() && $form->isValid()) {
125
            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

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