Completed
Pull Request — master (#4264)
by Craig
05:23
created

ExtensionController::compatibilityAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
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 Psr\Log\LoggerInterface;
17
use RuntimeException;
18
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
19
use Symfony\Component\HttpFoundation\RedirectResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\HttpFoundation\Response;
22
use Symfony\Component\Routing\Annotation\Route;
23
use Symfony\Component\Routing\RouterInterface;
24
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
25
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
26
use Zikula\BlocksModule\Entity\RepositoryInterface\BlockRepositoryInterface;
27
use Zikula\Bundle\CoreBundle\CacheClearer;
28
use Zikula\Bundle\CoreBundle\Composer\MetaData;
29
use Zikula\Bundle\CoreBundle\Controller\AbstractController;
30
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
31
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaKernel;
32
use Zikula\Bundle\FormExtensionBundle\Form\Type\DeletionType;
33
use Zikula\Component\SortableColumns\Column;
34
use Zikula\Component\SortableColumns\SortableColumns;
35
use Zikula\ExtensionsModule\AbstractExtension;
36
use Zikula\ExtensionsModule\Api\VariableApi;
37
use Zikula\ExtensionsModule\Constant;
38
use Zikula\ExtensionsModule\Entity\ExtensionEntity;
39
use Zikula\ExtensionsModule\Entity\RepositoryInterface\ExtensionRepositoryInterface;
40
use Zikula\ExtensionsModule\Event\ExtensionListPreReSyncEvent;
41
use Zikula\ExtensionsModule\Event\ExtensionPostCacheRebuildEvent;
42
use Zikula\ExtensionsModule\Form\Type\ExtensionInstallType;
43
use Zikula\ExtensionsModule\Form\Type\ExtensionModifyType;
44
use Zikula\ExtensionsModule\Helper\BundleSyncHelper;
45
use Zikula\ExtensionsModule\Helper\ExtensionDependencyHelper;
46
use Zikula\ExtensionsModule\Helper\ExtensionHelper;
47
use Zikula\ExtensionsModule\Helper\ExtensionStateHelper;
48
use Zikula\PermissionsModule\Annotation\PermissionCheck;
49
use Zikula\RoutesModule\Event\RoutesNewlyAvailableEvent;
50
use Zikula\ThemeModule\Engine\Annotation\Theme;
51
use Zikula\ThemeModule\Engine\Engine;
52
53
/**
54
 * @Route("")
55
 */
56
class ExtensionController extends AbstractController
57
{
58
    /**
59
     * @Route("/list/{page}", methods = {"GET"}, requirements={"page" = "\d+"})
60
     * @PermissionCheck("admin")
61
     * @Theme("admin")
62
     * @Template("@ZikulaExtensionsModule/Extension/list.html.twig")
63
     */
64
    public function listAction(
65
        Request $request,
66
        EventDispatcherInterface $eventDispatcher,
67
        ExtensionRepositoryInterface $extensionRepository,
68
        BundleSyncHelper $bundleSyncHelper,
69
        RouterInterface $router,
70
        int $page = 1
71
    ): array {
72
        $modulesJustInstalled = $request->query->get('justinstalled');
73
        if (!empty($modulesJustInstalled)) {
74
            // notify the event dispatcher that new routes are available (ids of modules just installed avail as args)
75
            $eventDispatcher->dispatch(new RoutesNewlyAvailableEvent(json_decode($modulesJustInstalled)));
76
        }
77
78
        $sortableColumns = new SortableColumns($router, 'zikulaextensionsmodule_extension_list');
79
        $sortableColumns->addColumns([new Column('displayname'), new Column('state')]);
80
        $sortableColumns->setOrderByFromRequest($request);
81
82
        $upgradedExtensions = [];
83
        $extensionListPreReSyncEvent = new ExtensionListPreReSyncEvent();
84
        $eventDispatcher->dispatch($extensionListPreReSyncEvent);
85
        if (1 === $page && !$extensionListPreReSyncEvent->isPropagationStopped()) {
86
            // regenerate the extension list only when viewing the first page
87
            $extensionsInFileSystem = $bundleSyncHelper->scanForBundles();
88
            $upgradedExtensions = $bundleSyncHelper->syncExtensions($extensionsInFileSystem);
89
        }
90
91
        $pageSize = $this->getVar('itemsperpage');
92
93
        $paginator = $extensionRepository->getPagedCollectionBy([], [
94
            $sortableColumns->getSortColumn()->getName() => $sortableColumns->getSortDirection()
95
        ], $page, $pageSize);
0 ignored issues
show
Bug introduced by
It seems like $pageSize can also be of type false; however, parameter $pageSize of Zikula\ExtensionsModule\...:getPagedCollectionBy() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

95
        ], $page, /** @scrutinizer ignore-type */ $pageSize);
Loading history...
96
        $paginator->setRoute('zikulaextensionsmodule_extension_list');
97
98
        return [
99
            'sort' => $sortableColumns->generateSortableColumns(),
100
            'paginator' => $paginator,
101
            'upgradedExtensions' => $upgradedExtensions
102
        ];
103
    }
104
105
    /**
106
     * @Route("/activate/{id}/{token}", methods = {"GET"}, requirements={"id" = "^[1-9]\d*$"})
107
     * @PermissionCheck("admin")
108
     *
109
     * Activate an extension.
110
     *
111
     * @throws AccessDeniedException Thrown if the CSRF token is invalid
112
     */
113
    public function activateAction(
114
        int $id,
115
        string $token,
116
        ExtensionRepositoryInterface $extensionRepository,
117
        ExtensionStateHelper $extensionStateHelper,
118
        LoggerInterface $zikulaLogger,
119
        CacheClearer $cacheClearer
120
    ): RedirectResponse {
121
        if (!$this->isCsrfTokenValid('activate-extension', $token)) {
122
            throw new AccessDeniedException();
123
        }
124
125
        /** @var ExtensionEntity $extension */
126
        $extension = $extensionRepository->find($id);
127
        $zikulaLogger->notice(sprintf('Extension activating'), ['name' => $extension->getName()]);
128
        if (Constant::STATE_NOTALLOWED === $extension->getState()) {
129
            $this->addFlash('error', $this->trans('Error! Activation of %name% not allowed.', ['%name%' => $extension->getName()]));
130
        } else {
131
            // Update state
132
            $extensionStateHelper->updateState($id, Constant::STATE_ACTIVE);
133
//            $cacheClearer->clear('symfony');
134
            $this->addFlash('status', $this->trans('Done! Activated %name%.', ['%name%' => $extension->getName()]));
135
        }
136
137
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
138
    }
139
140
    /**
141
     * @Route("/deactivate/{id}/{token}", methods = {"GET"}, requirements={"id" = "^[1-9]\d*$"})
142
     * @PermissionCheck("admin")
143
     *
144
     * Deactivate an extension
145
     *
146
     * @throws AccessDeniedException Thrown if the CSRF token is invalid
147
     */
148
    public function deactivateAction(
149
        int $id,
150
        string $token,
151
        ExtensionRepositoryInterface $extensionRepository,
152
        ExtensionStateHelper $extensionStateHelper,
153
        LoggerInterface $zikulaLogger,
154
        CacheClearer $cacheClearer
155
    ): RedirectResponse {
156
        if (!$this->isCsrfTokenValid('deactivate-extension', $token)) {
157
            throw new AccessDeniedException();
158
        }
159
160
        /** @var ExtensionEntity $extension */
161
        $extension = $extensionRepository->find($id);
162
        $zikulaLogger->notice(sprintf('Extension deactivating'), ['name' => $extension->getName()]);
163
        $defaultTheme = $this->getVariableApi()->get(VariableApi::CONFIG, 'defaulttheme');
164
        $adminTheme = $this->getVariableApi()->get('ZikulaAdminModule', 'admintheme');
165
166
        if (null !== $extension) {
167
            if (ZikulaKernel::isCoreExtension($extension->getName())) {
168
                $this->addFlash('error', $this->trans('Error! You cannot deactivate the %name%. It is required by the system.', ['%name%' => $extension->getName()]));
169
            } elseif (in_array($extension->getName(), [$defaultTheme, $adminTheme])) {
170
                $this->addFlash('error', $this->trans('Error! You cannot deactivate the %name%. The theme is in use.', ['%name%' => $extension->getName()]));
171
            } else {
172
                // Update state
173
                $extensionStateHelper->updateState($id, Constant::STATE_INACTIVE);
174
//                $cacheClearer->clear('symfony');
175
                $this->addFlash('status', $this->trans('Done! Deactivated %name%.', ['%name%' => $extension->getName()]));
176
            }
177
        }
178
179
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
180
    }
181
182
    /**
183
     * @Route("/modify/{id}/{forceDefaults}", requirements={"id" = "^[1-9]\d*$", "forceDefaults" = "0|1"})
184
     * @Theme("admin")
185
     * @Template("@ZikulaExtensionsModule/Extension/modify.html.twig")
186
     *
187
     * Modify a module.
188
     *
189
     * @return array|RedirectResponse
190
     * @throws AccessDeniedException Thrown if the user doesn't have admin permissions for modifying the extension
191
     */
192
    public function modifyAction(
193
        Request $request,
194
        ZikulaHttpKernelInterface $kernel,
195
        ExtensionEntity $extension,
196
        CacheClearer $cacheClearer,
197
        bool $forceDefaults = false
198
    ) {
199
        if (!$this->hasPermission('ZikulaExtensionsModule::modify', $extension->getName() . '::' . $extension->getId(), ACCESS_ADMIN)) {
200
            throw new AccessDeniedException();
201
        }
202
203
        /** @var AbstractExtension $extensionBundle */
204
        $extensionBundle = $kernel->getBundle($extension->getName());
205
        $metaData = $extensionBundle->getMetaData()->getFilteredVersionInfoArray();
206
207
        if ($forceDefaults) {
208
            $extension->setName($metaData['name']);
209
            $extension->setUrl($metaData['url']);
210
            $extension->setDescription($metaData['description']);
211
        }
212
213
        $form = $this->createForm(ExtensionModifyType::class, $extension);
214
        $form->handleRequest($request);
215
        if ($form->isSubmitted() && $form->isValid()) {
216
            if ($form->get('defaults')->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

216
            if ($form->get('defaults')->/** @scrutinizer ignore-call */ isClicked()) {
Loading history...
217
                $this->addFlash('info', 'Default values reloaded. Save to confirm.');
218
219
                return $this->redirectToRoute('zikulaextensionsmodule_extension_modify', ['id' => $extension->getId(), 'forceDefaults' => 1]);
220
            }
221
            if ($form->get('save')->isClicked()) {
222
                $em = $this->getDoctrine()->getManager();
223
                $em->persist($extension);
224
                $em->flush();
225
226
                $cacheClearer->clear('symfony.routing');
227
                $this->addFlash('status', 'Done! Extension updated.');
228
            } elseif ($form->get('cancel')->isClicked()) {
229
                $this->addFlash('status', 'Operation cancelled.');
230
            }
231
232
            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
233
        }
234
235
        return [
236
            'form' => $form->createView()
237
        ];
238
    }
239
240
    /**
241
     * @Route("/compatibility/{id}", methods = {"GET"}, requirements={"id" = "^[1-9]\d*$"})
242
     * @Theme("admin")
243
     * @Template("@ZikulaExtensionsModule/Extension/compatibility.html.twig")
244
     *
245
     * Display information of a module compatibility with the version of the core
246
     *
247
     * @throws AccessDeniedException Thrown if the user doesn't have admin permission to the requested module
248
     */
249
    public function compatibilityAction(ExtensionEntity $extension): array
250
    {
251
        if (!$this->hasPermission('ZikulaExtensionsModule::', $extension->getName() . '::' . $extension->getId(), ACCESS_ADMIN)) {
252
            throw new AccessDeniedException();
253
        }
254
255
        return [
256
            'extension' => $extension
257
        ];
258
    }
259
260
    /**
261
     * @Route("/install/{id}/{token}", requirements={"id" = "^[1-9]\d*$"})
262
     * @PermissionCheck("admin")
263
     * @Theme("admin")
264
     * @Template("@ZikulaExtensionsModule/Extension/install.html.twig")
265
     *
266
     * Install and initialise an extension.
267
     *
268
     * @return array|RedirectResponse
269
     * @throws AccessDeniedException Thrown if the CSRF token is invalid
270
     */
271
    public function installAction(
272
        Request $request,
273
        ExtensionEntity $extension,
274
        string $token,
275
        ZikulaHttpKernelInterface $kernel,
276
        ExtensionRepositoryInterface $extensionRepository,
277
        ExtensionHelper $extensionHelper,
278
        ExtensionStateHelper $extensionStateHelper,
279
        ExtensionDependencyHelper $dependencyHelper,
280
        CacheClearer $cacheClearer
281
    ) {
282
        $id = $extension->getId();
283
        if (!$this->isCsrfTokenValid('install-extension', $token)) {
284
            throw new AccessDeniedException();
285
        }
286
287
        if (!$kernel->isBundle($extension->getName())) {
288
            $extensionStateHelper->updateState($id, Constant::STATE_TRANSITIONAL);
289
//            $cacheClearer->clear('symfony');
290
291
            return $this->redirectToRoute('zikulaextensionsmodule_extension_install', ['id' => $id, 'token' => $token]);
292
        }
293
        $unsatisfiedDependencies = $dependencyHelper->getUnsatisfiedExtensionDependencies($extension);
294
        $form = $this->createForm(ExtensionInstallType::class, [
295
            'dependencies' => $this->formatDependencyCheckboxArray($extensionRepository, $unsatisfiedDependencies)
296
        ]);
297
        $hasNoUnsatisfiedDependencies = empty($unsatisfiedDependencies);
298
        $form->handleRequest($request);
299
        if ($hasNoUnsatisfiedDependencies || ($form->isSubmitted() && $form->isValid())) {
300
            if ($hasNoUnsatisfiedDependencies || $form->get('install')->isClicked()) {
301
                $extensionsInstalled = [];
302
                $data = $form->getData();
303
                foreach ($data['dependencies'] as $dependencyId => $installSelected) {
304
                    if (!$installSelected && MetaData::DEPENDENCY_REQUIRED !== $unsatisfiedDependencies[$dependencyId]->getStatus()) {
305
                        continue;
306
                    }
307
                    $dependencyExtensionEntity = $extensionRepository->get($unsatisfiedDependencies[$dependencyId]->getModname());
308
                    if (isset($dependencyExtensionEntity)) {
309
                        if (!$extensionHelper->install($dependencyExtensionEntity)) {
310
                            $this->addFlash('error', $this->trans('Failed to install dependency "%name%"!', ['%name%' => $dependencyExtensionEntity->getName()]));
311
312
                            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
313
                        }
314
                        $extensionsInstalled[] = $dependencyExtensionEntity->getId();
315
                        $this->addFlash('status', $this->trans('Installed dependency "%name%".', ['%name%' => $dependencyExtensionEntity->getName()]));
316
                    } else {
317
                        $this->addFlash('warning', $this->trans('Warning: could not install selected dependency "%name%".', ['%name%' => $unsatisfiedDependencies[$dependencyId]->getModname()]));
318
                    }
319
                }
320
                if ($extensionHelper->install($extension)) {
321
                    $this->addFlash('status', $this->trans('Done! Installed "%name%".', ['%name%' => $extension->getName()]));
322
                    $extensionsInstalled[] = $id;
323
//                    $cacheClearer->clear('symfony');
324
325
                    return $this->redirectToRoute('zikulaextensionsmodule_extension_postinstall', ['extensions' => json_encode($extensionsInstalled)]);
326
                }
327
                $extensionStateHelper->updateState($id, Constant::STATE_UNINITIALISED);
328
                $this->addFlash('error', $this->trans('Initialization of "%name%" failed!', ['%name%' => $extension->getName()]));
329
            }
330
            if ($form->get('cancel')->isClicked()) {
331
                $extensionStateHelper->updateState($id, Constant::STATE_UNINITIALISED);
332
                $this->addFlash('status', 'Operation cancelled.');
333
            }
334
335
            return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
336
        }
337
338
        return [
339
            'dependencies' => $unsatisfiedDependencies,
340
            'extension' => $extension,
341
            'form' => $form->createView()
342
        ];
343
    }
344
345
    /**
346
     * Post-installation action to trigger the MODULE_POSTINSTALL event.
347
     * The additional Action is required because this event must occur AFTER the rebuild of the cache which occurs on Request.
348
     *
349
     * @Route("/postinstall/{extensions}", methods = {"GET"})
350
     */
351
    public function postInstallAction(
352
        ExtensionRepositoryInterface $extensionRepository,
353
        ZikulaHttpKernelInterface $kernel,
354
        EventDispatcherInterface $eventDispatcher,
355
        string $extensions = null
356
    ): RedirectResponse {
357
        if (!empty($extensions)) {
358
            $extensions = json_decode($extensions);
359
            foreach ($extensions as $extensionId) {
360
                /** @var ExtensionEntity $extensionEntity */
361
                $extensionEntity = $extensionRepository->find($extensionId);
362
                if (null === $extensionRepository) {
363
                    continue;
364
                }
365
                /** @var AbstractExtension $extensionBundle */
366
                $extensionBundle = $kernel->getBundle($extensionEntity->getName());
367
                if (null === $extensionBundle) {
368
                    continue;
369
                }
370
                $eventDispatcher->dispatch(new ExtensionPostCacheRebuildEvent($extensionBundle, $extensionEntity));
371
            }
372
        }
373
374
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list', ['justinstalled' => json_encode($extensions)]);
375
    }
376
377
    /**
378
     * Create array suitable for checkbox FormType [[ID => bool][ID => bool]].
379
     */
380
    private function formatDependencyCheckboxArray(
381
        ExtensionRepositoryInterface $extensionRepository,
382
        array $dependencies
383
    ): array {
384
        $return = [];
385
        foreach ($dependencies as $dependency) {
386
            /** @var ExtensionEntity $dependencyExtension */
387
            $dependencyExtension = $extensionRepository->get($dependency->getModname());
388
            $return[$dependency->getId()] = null !== $dependencyExtension;
389
        }
390
391
        return $return;
392
    }
393
394
    /**
395
     * @Route("/upgrade/{id}/{token}", requirements={"id" = "^[1-9]\d*$"})
396
     * @PermissionCheck("admin")
397
     *
398
     * Upgrade an extension.
399
     *
400
     * @throws AccessDeniedException Thrown if the CSRF token is invalid
401
     */
402
    public function upgradeAction(
403
        ExtensionEntity $extension,
404
        $token,
405
        ExtensionHelper $extensionHelper
406
    ): RedirectResponse {
407
        if (!$this->isCsrfTokenValid('upgrade-extension', $token)) {
408
            throw new AccessDeniedException();
409
        }
410
411
        $result = $extensionHelper->upgrade($extension);
412
        if ($result) {
413
            $this->addFlash('status', $this->trans('%name% upgraded to new version and activated.', ['%name%' => $extension->getDisplayname()]));
414
        } else {
415
            $this->addFlash('error', 'Extension upgrade failed!');
416
        }
417
418
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
419
    }
420
421
    /**
422
     * @Route("/uninstall/{id}/{token}", requirements={"id" = "^[1-9]\d*$"})
423
     * @PermissionCheck("admin")
424
     * @Theme("admin")
425
     * @Template("@ZikulaExtensionsModule/Extension/uninstall.html.twig")
426
     *
427
     * Uninstall an extension.
428
     *
429
     * @return array|Response|RedirectResponse
430
     * @throws AccessDeniedException Thrown if the CSRF token is invalid
431
     */
432
    public function uninstallAction(
433
        Request $request,
434
        ExtensionEntity $extension,
435
        string $token,
436
        ZikulaHttpKernelInterface $kernel,
437
        BlockRepositoryInterface $blockRepository,
438
        ExtensionHelper $extensionHelper,
439
        ExtensionStateHelper $extensionStateHelper,
440
        ExtensionDependencyHelper $dependencyHelper,
441
        CacheClearer $cacheClearer
442
    ) {
443
        if (!$this->isCsrfTokenValid('uninstall-extension', $token)) {
444
            throw new AccessDeniedException();
445
        }
446
447
        if (Constant::STATE_MISSING === $extension->getState()) {
448
            throw new RuntimeException($this->trans('Error! The requested extension cannot be uninstalled because its files are missing!'));
449
        }
450
        if (!$kernel->isBundle($extension->getName())) {
451
            $extensionStateHelper->updateState($extension->getId(), Constant::STATE_TRANSITIONAL);
452
//            $cacheClearer->clear('symfony');
453
        }
454
        $requiredDependents = $dependencyHelper->getDependentExtensions($extension);
455
        $blocks = $blockRepository->findBy(['module' => $extension]);
456
457
        $form = $this->createForm(DeletionType::class, [], [
458
            'action' => $this->generateUrl('zikulaextensionsmodule_extension_uninstall', [
459
                'id' => $extension->getId(),
460
                'token' => $token
461
            ]),
462
        ]);
463
        $form->handleRequest($request);
464
        if ($form->isSubmitted() && $form->isValid()) {
465
            if ($form->get('delete')->isClicked()) {
466
                // remove dependent extensions
467
                if (!$extensionHelper->uninstallArray($requiredDependents)) {
468
                    $this->addFlash('error', 'Error: Could not uninstall dependent extensions.');
469
470
                    return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
471
                }
472
                // remove blocks
473
                $blockRepository->remove($blocks);
474
475
                // remove the extension
476
                if ($extensionHelper->uninstall($extension)) {
477
                    $this->addFlash('status', 'Done! Uninstalled extension.');
478
                } else {
479
                    $this->addFlash('error', 'Extension removal failed! (note: blocks and dependents may have been removed)');
480
                }
481
            } elseif ($form->get('cancel')->isClicked()) {
482
                $this->addFlash('status', 'Operation cancelled.');
483
            }
484
485
            return $this->redirectToRoute('zikulaextensionsmodule_extension_postuninstall');
486
        }
487
488
        return [
489
            'form' => $form->createView(),
490
            'extension' => $extension,
491
            'blocks' => $blocks,
492
            'requiredDependents' => $requiredDependents
493
        ];
494
    }
495
496
    /**
497
     * @Route("/post-uninstall")
498
     * @PermissionCheck("admin")
499
     *
500
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
501
     */
502
    public function postUninstallAction(CacheClearer $cacheClearer)
503
    {
504
        $cacheClearer->clear('symfony');
505
506
        return $this->redirectToRoute('zikulaextensionsmodule_extension_list');
507
    }
508
509
    /**
510
     * @Route("/theme-preview/{themeName}")
511
     * @PermissionCheck("admin")
512
     */
513
    public function previewAction(Engine $engine, string $themeName): Response
514
    {
515
        $engine->setActiveTheme($themeName);
516
        $this->addFlash('warning', 'Please note that blocks may appear out of place or even missing in a theme preview because position names are not consistent from theme to theme.');
517
518
        return $this->forward('Zikula\Bundle\CoreBundle\Controller\MainController::homeAction');
519
    }
520
}
521