Completed
Push — master ( a9a30f...65086f )
by Axel
24:23 queued 19:19
created

AdminController::adminheaderAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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\AdminModule\Controller;
15
16
use Doctrine\ORM\Tools\Pagination\Paginator;
17
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
18
use Symfony\Component\HttpFoundation\RedirectResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\Routing\Annotation\Route;
22
use Symfony\Component\Routing\Exception\RouteNotFoundException;
23
use Symfony\Component\Routing\RouterInterface;
24
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
25
use Zikula\AdminModule\Entity\AdminCategoryEntity;
26
use Zikula\AdminModule\Entity\RepositoryInterface\AdminCategoryRepositoryInterface;
27
use Zikula\AdminModule\Entity\RepositoryInterface\AdminModuleRepositoryInterface;
28
use Zikula\AdminModule\Form\Type\AdminCategoryType;
29
use Zikula\AdminModule\Helper\AdminLinksHelper;
30
use Zikula\Bundle\CoreBundle\Controller\AbstractController;
31
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
32
use Zikula\Bundle\FormExtensionBundle\Form\Type\DeletionType;
33
use Zikula\ExtensionsModule\Api\ApiInterface\CapabilityApiInterface;
34
use Zikula\MenuModule\ExtensionMenu\ExtensionMenuCollector;
35
use Zikula\MenuModule\ExtensionMenu\ExtensionMenuInterface;
36
use Zikula\ThemeModule\Engine\Annotation\Theme;
37
38
/**
39
 * NOTE: intentionally no class level route setting here
40
 *
41
 * Administrative controllers for the admin module
42
 */
43
class AdminController extends AbstractController
44
{
45
    /**
46
     * @Route("")
47
     *
48
     * The main administration function.
49
     */
50
    public function indexAction(): RedirectResponse
51
    {
52
        // Security check will be done in view()
53
        return $this->redirectToRoute('zikulaadminmodule_admin_view');
54
    }
55
56
    /**
57
     * @Route("/categories/{startnum}", methods = {"GET"}, requirements={"startnum" = "\d+"})
58
     * @Theme("admin")
59
     * @Template("@ZikulaAdminModule/Admin/view.html.twig")
60
     *
61
     * Views all admin categories.
62
     *
63
     * @throws AccessDeniedException Thrown if the user doesn't have edit permission to the module
64
     */
65
    public function viewAction(AdminCategoryRepositoryInterface $repository, int $startnum = 0): array
66
    {
67
        if (!$this->hasPermission('ZikulaAdminModule::', '::', ACCESS_EDIT)) {
68
            throw new AccessDeniedException();
69
        }
70
71
        $itemsPerPage = $this->getVar('itemsperpage');
72
73
        $categories = [];
74
        /** @var Paginator $items */
75
        $items = $repository->getPagedCategories(['sortorder' => 'ASC'], $itemsPerPage, $startnum);
0 ignored issues
show
Bug introduced by
It seems like $itemsPerPage can also be of type false; however, parameter $offset of Zikula\AdminModule\Entit...e::getPagedCategories() 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

75
        $items = $repository->getPagedCategories(['sortorder' => 'ASC'], /** @scrutinizer ignore-type */ $itemsPerPage, $startnum);
Loading history...
76
77
        foreach ($items as $item) {
78
            if ($this->hasPermission('ZikulaAdminModule::', $item['name'] . '::' . $item['cid'], ACCESS_READ)) {
79
                $categories[] = $item;
80
            }
81
        }
82
83
        return [
84
            'categories' => $categories,
85
            'pager' => [
86
                'amountOfItems' => $items->count(),
87
                'itemsPerPage' => $itemsPerPage
88
            ]
89
        ];
90
    }
91
92
    /**
93
     * @Route("/newcategory")
94
     * @Theme("admin")
95
     * @Template("@ZikulaAdminModule/Admin/editCategory.html.twig")
96
     *
97
     * Displays and handles a form for the user to input the details of the new category.
98
     *
99
     * @return array|RedirectResponse
100
     * @throws AccessDeniedException Thrown if the user doesn't have permission to add a category
101
     */
102
    public function newcatAction(Request $request)
103
    {
104
        if (!$this->hasPermission('ZikulaAdminModule::Item', '::', ACCESS_ADD)) {
105
            throw new AccessDeniedException();
106
        }
107
108
        $form = $this->createForm(AdminCategoryType::class, new AdminCategoryEntity());
109
        $form->handleRequest($request);
110
        if ($form->isSubmitted() && $form->isValid()) {
111
            if ($form->get('save')->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

111
            if ($form->get('save')->/** @scrutinizer ignore-call */ isClicked()) {
Loading history...
112
                $adminCategory = $form->getData();
113
                $this->getDoctrine()->getManager()->persist($adminCategory);
114
                $this->getDoctrine()->getManager()->flush();
115
                $this->addFlash('status', 'Done! Created new category.');
116
            } elseif ($form->get('cancel')->isClicked()) {
117
                $this->addFlash('status', 'Operation cancelled.');
118
            }
119
120
            return $this->redirectToRoute('zikulaadminmodule_admin_view');
121
        }
122
123
        return [
124
            'form' => $form->createView()
125
        ];
126
    }
127
128
    /**
129
     * @Route("/modifycategory/{cid}", requirements={"cid" = "^[1-9]\d*$"})
130
     * @Theme("admin")
131
     * @Template("@ZikulaAdminModule/Admin/editCategory.html.twig")
132
     *
133
     * Displays and handles a modify category form.
134
     *
135
     * @return array|RedirectResponse
136
     * @throws AccessDeniedException Thrown if the user doesn't have permission to edit a category
137
     */
138
    public function modifyAction(Request $request, AdminCategoryEntity $category)
139
    {
140
        if (!$this->hasPermission('ZikulaAdminModule::Category', $category['name'] . '::' . $category->getCid(), ACCESS_EDIT)) {
141
            throw new AccessDeniedException();
142
        }
143
144
        $form = $this->createForm(AdminCategoryType::class, $category);
145
        $form->handleRequest($request);
146
        if ($form->isSubmitted() && $form->isValid()) {
147
            if ($form->get('save')->isClicked()) {
148
                $category = $form->getData();
149
                if (!$this->hasPermission('ZikulaAdminModule::Category', $category->getName() . '::' . $category->getCid(), ACCESS_EDIT)) {
150
                    throw new AccessDeniedException();
151
                }
152
                $this->getDoctrine()->getManager()->flush();
153
                $this->addFlash('status', 'Done! Saved category.');
154
            } elseif ($form->get('cancel')->isClicked()) {
155
                $this->addFlash('status', 'Operation cancelled.');
156
            }
157
158
            return $this->redirectToRoute('zikulaadminmodule_admin_view');
159
        }
160
161
        return [
162
            'form' => $form->createView()
163
        ];
164
    }
165
166
    /**
167
     * @Route("/deletecategory/{cid}", requirements={"cid" = "^[1-9]\d*$"})
168
     * @Theme("admin")
169
     * @Template("@ZikulaAdminModule/Admin/delete.html.twig")
170
     *
171
     * Deletes an admin category.
172
     *
173
     * @return array|RedirectResponse
174
     * @throws AccessDeniedException Thrown if the user doesn't have permission to edit a category
175
     */
176
    public function deleteAction(Request $request, AdminCategoryEntity $category)
177
    {
178
        if (!$this->hasPermission('ZikulaAdminModule::Category', $category->getName() . '::' . $category->getCid(), ACCESS_DELETE)) {
179
            throw new AccessDeniedException();
180
        }
181
182
        $form = $this->createForm(DeletionType::class, $category);
183
        $form->handleRequest($request);
184
        if ($form->isSubmitted() && $form->isValid()) {
185
            if ($form->get('delete')->isClicked()) {
186
                $category = $form->getData();
187
                $this->getDoctrine()->getManager()->remove($category);
188
                $this->getDoctrine()->getManager()->flush();
189
                $this->addFlash('status', 'Done! Category deleted.');
190
            } elseif ($form->get('cancel')->isClicked()) {
191
                $this->addFlash('status', 'Operation cancelled.');
192
            }
193
194
            return $this->redirectToRoute('zikulaadminmodule_admin_view');
195
        }
196
197
        return [
198
            'form' => $form->createView(),
199
            'category' => $category
200
        ];
201
    }
202
203
    /**
204
     * @Route("/panel/{acid}", methods = {"GET"}, requirements={"acid" = "^[1-9]\d*$"})
205
     * @Theme("admin")
206
     * @Template("@ZikulaAdminModule/Admin/adminpanel.html.twig")
207
     *
208
     * Displays main admin panel for a category.
209
     *
210
     * @return array|Response
211
     * @throws AccessDeniedException Thrown if the user doesn't have edit permission for the module
212
     */
213
    public function adminpanelAction(
214
        ZikulaHttpKernelInterface $kernel,
215
        AdminCategoryRepositoryInterface $adminCategoryRepository,
216
        AdminModuleRepositoryInterface $adminModuleRepository,
217
        CapabilityApiInterface $capabilityApi,
218
        RouterInterface $router,
219
        AdminLinksHelper $adminLinksHelper,
220
        ExtensionMenuCollector $extensionMenuCollector,
221
        int $acid = null
222
    ) {
223
        if (!$this->hasPermission('::', '::', ACCESS_EDIT)) {
224
            // suppress admin display - return to index.
225
            if (!$this->hasPermission('ZikulaAdminModule::', '::', ACCESS_EDIT)) {
226
                throw new AccessDeniedException();
227
            }
228
        }
229
230
        if (!$this->getVar('ignoreinstallercheck') && 'dev' === $kernel->getEnvironment()) {
231
            // check if the Zikula Recovery Console exists
232
            $zrcExists = file_exists('zrc.php');
233
            // check if upgrade scripts exist
234
            if (true === $zrcExists) {
235
                return $this->render('@ZikulaAdminModule/Admin/warning.html.twig', [
236
                    'zrcExists' => $zrcExists
237
                ]);
238
            }
239
        }
240
241
        // Now prepare the display of the admin panel by getting the relevant info.
242
243
        // cid isn't set, so go to the default category
244
        if (empty($acid)) {
245
            $acid = $this->getVar('startcategory');
246
        }
247
248
        $templateParameters = [
249
            // Add category menu to output
250
            'menu' => $this->categorymenuAction(
251
                $adminCategoryRepository,
252
                $adminModuleRepository,
253
                $capabilityApi,
254
                $router,
255
                $adminLinksHelper,
256
                $acid
257
            )->getContent()
258
        ];
259
260
        // Check to see if we have access to the requested category.
261
        if (!$this->hasPermission('ZikulaAdminModule::', "::${acid}", ACCESS_ADMIN)) {
262
            $acid = -1;
263
        }
264
265
        // Get details for selected category
266
        $category = null;
267
        if ($acid > 0) {
268
            $category = $adminCategoryRepository->findOneBy(['cid' => $acid]);
269
        }
270
271
        if (!$category) {
272
            // get the default category
273
            $acid = $this->getVar('startcategory');
274
275
            // Check to see if we have access to the requested category.
276
            if (!$this->hasPermission('ZikulaAdminModule::', "::${acid}", ACCESS_ADMIN)) {
277
                throw new AccessDeniedException();
278
            }
279
280
            $category = $adminCategoryRepository->findOneBy(['cid' => $acid]);
281
        }
282
283
        // assign the category
284
        $templateParameters['category'] = $category;
285
286
        $displayNameType = $this->getVar('displaynametype', 1);
287
        $moduleEntities = $adminModuleRepository->findAll();
288
289
        // get admin capable modules
290
        $adminModules = $capabilityApi->getExtensionsCapableOf('admin');
291
        $adminLinks = [];
292
        foreach ($adminModules as $adminModule) {
293
            if (!$this->hasPermission($adminModule['name'] . '::', 'ANY', ACCESS_EDIT)) {
294
                continue;
295
            }
296
297
            $moduleId = (int)$adminModule['id'];
298
            $moduleCategory = $adminCategoryRepository->getModuleCategory($moduleId);
299
            $catid = null !== $moduleCategory ? $moduleCategory['cid'] : 0;
300
301
            $sortOrder = -1;
302
            foreach ($moduleEntities as $association) {
303
                if ($association['mid'] !== $adminModule['id']) {
304
                    continue;
305
                }
306
307
                $sortOrder = $association['sortorder'];
308
                break;
309
            }
310
311
            if ($catid === $acid || (false === $catid && $acid === $this->getVar('defaultcategory'))) {
312
                $menuText = '';
313
                if (1 === $displayNameType) {
314
                    $menuText = $adminModule['displayname'];
315
                } elseif (2 === $displayNameType) {
316
                    $menuText = $adminModule['name'];
317
                } elseif (3 === $displayNameType) {
318
                    $menuText = $adminModule['displayname'] . ' (' . $adminModule['name'] . ')';
319
                }
320
321
                try {
322
                    $menuTextUrl = isset($adminModule['capabilities']['admin']['route'])
323
                        ? $router->generate($adminModule['capabilities']['admin']['route'])
324
                        : '';
325
                } catch (RouteNotFoundException $routeNotFoundException) {
326
                    $menuTextUrl = 'javascript:void(0)';
327
                    $menuText .= ' (<i class="fas fa-exclamation-triangle"></i> ' . $this->trans('invalid route') . ')';
328
                }
329
330
                $moduleName = (string)$adminModule['name'];
331
                /** @var \Knp\Menu\ItemInterface $extensionMenu */
332
                $extensionMenu = $extensionMenuCollector->get($moduleName, ExtensionMenuInterface::TYPE_ADMIN);
333
                if (isset($extensionMenu)) {
334
                    $extensionMenu->setChildrenAttribute('class', 'dropdown-menu');
335
                }
336
337
                $adminLinks[] = [
338
                    'menuTextUrl' => $menuTextUrl,
339
                    'menuText' => $menuText,
340
                    'menuTextTitle' => $adminModule['description'],
341
                    'moduleName' => $adminModule['name'],
342
                    'adminIcon' => $adminModule['icon'],
343
                    'id' => $adminModule['id'],
344
                    'order' => $sortOrder,
345
                    'extensionMenu' => $extensionMenu
346
                ];
347
            }
348
        }
349
        $templateParameters['adminLinks'] = $adminLinksHelper->sortAdminModsByOrder($adminLinks);
350
351
        return $templateParameters;
352
    }
353
354
    /**
355
     * @Route("/categorymenu/{acid}", methods = {"GET"}, requirements={"acid" = "^[1-9]\d*$"})
356
     * @Theme("admin")
357
     *
358
     * Displays main category menu.
359
     */
360
    public function categorymenuAction(
361
        AdminCategoryRepositoryInterface $adminCategoryRepository,
362
        AdminModuleRepositoryInterface $adminModuleRepository,
363
        CapabilityApiInterface $capabilityApi,
364
        RouterInterface $router,
365
        AdminLinksHelper $adminLinksHelper,
366
        int $acid = null
367
    ): Response {
368
        $acid = empty($acid) ? $this->getVar('startcategory') : $acid;
369
370
        // Get all categories
371
        $categories = [];
372
        $items = $adminCategoryRepository->findBy([], ['sortorder' => 'ASC']);
373
        foreach ($items as $item) {
374
            if ($this->hasPermission('ZikulaAdminModule::', $item['name'] . '::' . $item['cid'], ACCESS_READ)) {
375
                $categories[] = $item;
376
            }
377
        }
378
379
        $moduleEntities = $adminModuleRepository->findAll();
380
381
        // get admin capable modules
382
        $adminModules = $capabilityApi->getExtensionsCapableOf('admin');
383
        $adminLinks = [];
384
        foreach ($adminModules as $adminModule) {
385
            if (!$this->hasPermission($adminModule['name'] . '::', '::', ACCESS_EDIT)) {
386
                continue;
387
            }
388
389
            $menuText = $adminModule['displayname'];
390
            try {
391
                $menuTextUrl = isset($adminModule['capabilities']['admin']['route'])
392
                    ? $router->generate($adminModule['capabilities']['admin']['route'])
393
                    : '';
394
            } catch (RouteNotFoundException $routeNotFoundException) {
395
                $menuTextUrl = 'javascript:void(0)';
396
                $menuText .= ' (<i class="fas fa-exclamation-triangle"></i> ' . $this->trans('invalid route') . ')';
397
            }
398
399
            $moduleId = (int)$adminModule['id'];
400
            $moduleCategory = $adminCategoryRepository->getModuleCategory($moduleId);
401
            $catid = null !== $moduleCategory ? $moduleCategory['cid'] : 0;
402
403
            $sortOrder = -1;
404
            foreach ($moduleEntities as $association) {
405
                if ($association['mid'] !== $adminModule['id']) {
406
                    continue;
407
                }
408
409
                $sortOrder = $association['sortorder'];
410
                break;
411
            }
412
413
            $adminLinks[$catid][] = [
414
                'menuTextUrl' => $menuTextUrl,
415
                'menuText' => $menuText,
416
                'menuTextTitle' => $adminModule['description'],
417
                'moduleName' => $adminModule['name'],
418
                'order' => $sortOrder,
419
                'id' => $adminModule['id'],
420
                'icon' => $adminModule['icon']
421
            ];
422
        }
423
424
        foreach ($adminLinks as $categoryId => $links) {
425
            $adminLinks[$categoryId] = $adminLinksHelper->sortAdminModsByOrder($links);
426
        }
427
428
        $menuOptions = [];
429
        $possibleCategoryIds = [];
430
        $permission = false;
431
432
        if (isset($categories) && is_array($categories)) {
433
            foreach ($categories as $category) {
434
                // only categories containing modules where the current user has permissions will
435
                // be shown, all others will be hidden
436
                // admin will see all categories
437
                if ($this->hasPermission('.*', '.*', ACCESS_ADMIN)
438
                    || (isset($adminLinks[$category['cid']]) && count($adminLinks[$category['cid']]))
439
                ) {
440
                    $menuOption = [
441
                        'url' => $router->generate('zikulaadminmodule_admin_adminpanel', ['acid' => $category['cid']]),
442
                        'title' => $category['name'],
443
                        'description' => $category['description'],
444
                        'cid' => $category['cid'],
445
                        'items' => $adminLinks[$category['cid']] ?? []
446
                    ];
447
448
                    $menuOptions[$category['cid']] = $menuOption;
449
                    $possibleCategoryIds[] = $category['cid'];
450
451
                    if ($acid === $category['cid']) {
452
                        $permission = true;
453
                    }
454
                }
455
            }
456
        }
457
458
        // if permission is false we are not allowed to see this category because its
459
        // empty and we are not admin
460
        if (false === $permission) {
0 ignored issues
show
introduced by
The condition false === $permission is always true.
Loading history...
461
            // show the first category
462
            $acid = !empty($possibleCategoryIds) ? (int)$possibleCategoryIds[0] : null;
463
        }
464
465
        return $this->render('@ZikulaAdminModule/Admin/categoryMenu.html.twig', [
466
            'currentCategory' => $acid,
467
            'menuOptions' => $menuOptions
468
        ]);
469
    }
470
}
471