Completed
Push — master ( 86e506...1e27b6 )
by Axel
06:39
created

HookController::changeProviderAreaOrderAction()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 41
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 18
nc 7
nop 6
dl 0
loc 41
rs 8.4444
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\Bundle\HookBundle\Controller;
15
16
use InvalidArgumentException;
17
use RuntimeException;
18
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
19
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
20
use Symfony\Component\HttpFoundation\JsonResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\RequestStack;
23
use Symfony\Component\Routing\Annotation\Route;
24
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
25
use Symfony\Contracts\Translation\TranslatorInterface;
26
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
27
use Zikula\Bundle\CoreBundle\Translation\TranslatorTrait;
28
use Zikula\Bundle\HookBundle\Collector\HookCollectorInterface;
29
use Zikula\Bundle\HookBundle\Dispatcher\HookDispatcherInterface;
30
use Zikula\Bundle\HookBundle\Helper\HookUiHelper;
31
use Zikula\ExtensionsModule\Entity\ExtensionEntity;
32
use Zikula\PermissionsModule\Api\ApiInterface\PermissionApiInterface;
33
use Zikula\ThemeModule\Engine\Annotation\Theme;
34
35
/**
36
 * Class HookController
37
 * @Route("/hooks")
38
 */
39
class HookController extends AbstractController
40
{
41
    use TranslatorTrait;
42
43
    /**
44
     * @Route("/{moduleName}", methods = {"GET"}, options={"zkNoBundlePrefix" = 1})
45
     * @Theme("admin")
46
     * @Template("@ZikulaHook/Hook/edit.html.twig")
47
     *
48
     * Display hooks user interface
49
     *
50
     * @throws AccessDeniedException Thrown if the user doesn't have admin permissions over the module
51
     */
52
    public function editAction(
53
        RequestStack $requestStack,
54
        PermissionApiInterface $permissionApi,
55
        HookCollectorInterface $collector,
56
        HookDispatcherInterface $dispatcher,
57
        HookUiHelper $hookUiHelper,
58
        string $moduleName
59
    ): array {
60
        $templateParameters = [];
61
        // get module's name and assign it to template
62
        $templateParameters['currentmodule'] = $moduleName;
63
64
        // check if user has admin permission on this module
65
        if (!$permissionApi->hasPermission($moduleName . '::', '::', ACCESS_ADMIN)) {
66
            throw new AccessDeniedException();
67
        }
68
69
        // find out the capabilities of the module
70
        $isProvider = $collector->isCapable($moduleName, HookCollectorInterface::HOOK_PROVIDER);
71
        $templateParameters['isProvider'] = $isProvider;
72
73
        $isSubscriber = $collector->isCapable($moduleName, HookCollectorInterface::HOOK_SUBSCRIBER);
74
        $templateParameters['isSubscriber'] = $isSubscriber;
75
76
        $isSubscriberSelfCapable = $collector->isCapable($moduleName, HookCollectorInterface::HOOK_SUBSCRIBE_OWN);
77
        $templateParameters['isSubscriberSelfCapable'] = $isSubscriberSelfCapable;
78
        $templateParameters['providerAreas'] = [];
79
80
        $providers = $collector->getProviders();
81
        $subscribers = $collector->getSubscribers();
82
83
        // get areas of module and bundle titles also
84
        if ($isProvider) {
85
            $providerAreas = $collector->getProviderAreasByOwner($moduleName);
86
            $templateParameters['providerAreas'] = $providerAreas;
87
88
            $providerAreasToTitles = [];
89
            foreach ($providerAreas as $providerArea) {
90
                if (isset($providers[$providerArea])) {
91
                    $providerAreasToTitles[$providerArea] = $providers[$providerArea]->getTitle();
92
                }
93
            }
94
            $templateParameters['providerAreasToTitles'] = $providerAreasToTitles;
95
        }
96
        $templateParameters['subscriberAreas'] = [];
97
        $templateParameters['hookSubscribers'] = [];
98
99
        if ($isSubscriber) {
100
            $subscriberAreas = $collector->getSubscriberAreasByOwner($moduleName);
101
            $templateParameters['subscriberAreas'] = $subscriberAreas;
102
103
            $areasInfo = $hookUiHelper->prepareSubscriberAreasForSubscriber($subscriberAreas, $subscribers);
104
            $templateParameters['subscriberAreasToTitles'] = $areasInfo['titles'];
105
            $templateParameters['subscriberAreasToCategories'] = $areasInfo['categories'];
106
            $templateParameters['subscriberAreasAndCategories'] = $areasInfo['categoryGroups'];
107
        }
108
109
        // get available subscribers that can attach to provider
110
        if ($isProvider && !empty($providerAreas)) {
111
            [$hookSubscribers, $amountOfAvailableSubscriberAreas] = $hookUiHelper->prepareAvailableSubscriberAreasForProvider($moduleName, $subscribers);
112
            $templateParameters['hookSubscribers'] = $hookSubscribers;
113
            $templateParameters['amountOfAvailableSubscriberAreas'] = $amountOfAvailableSubscriberAreas;
114
        } else {
115
            $templateParameters['amountOfAvailableSubscriberAreas'] = 0;
116
        }
117
118
        // get providers that are already attached to the subscriber
119
        // and providers that can attach to the subscriber
120
        if ($isSubscriber && !empty($subscriberAreas)) {
121
            // get current sorting
122
            [$currentSorting, $currentSortingTitles, $amountOfAttachedProviderAreas] = $hookUiHelper->prepareAttachedProvidersForSubscriber($subscriberAreas, $providers);
123
            $templateParameters['areasSorting'] = $currentSorting;
124
            $templateParameters['areasSortingTitles'] = $currentSortingTitles;
125
            $templateParameters['amountOfAttachedProviderAreas'] = $amountOfAttachedProviderAreas;
126
127
            [$hookProviders, $amountOfAvailableProviderAreas] = $hookUiHelper->prepareAvailableProviderAreasForSubscriber($moduleName, $providers, $isSubscriberSelfCapable);
128
            $templateParameters['hookProviders'] = $hookProviders;
129
            $templateParameters['amountOfAvailableProviderAreas'] = $amountOfAvailableProviderAreas;
130
        } else {
131
            $templateParameters['hookProviders'] = [];
132
        }
133
        $templateParameters['hookDispatcher'] = $dispatcher;
134
        $request = $requestStack->getCurrentRequest();
135
        $request->attributes->set('_zkModule', $moduleName);
136
        $request->attributes->set('_zkType', 'admin');
137
        $request->attributes->set('_zkFunc', 'Hooks');
138
139
        return $templateParameters;
140
    }
141
142
    /**
143
     * @Route("/togglestatus", methods = {"POST"}, options={"expose"=true})
144
     *
145
     * Attach/detach a subscriber area to a provider area
146
     *
147
     * @throws InvalidArgumentException Thrown if either the subscriber, provider or subscriberArea parameters are empty
148
     * @throws RuntimeException Thrown if either the subscriber or provider module isn't available
149
     * @throws AccessDeniedException Thrown if the user doesn't have admin access to either the subscriber or provider modules
150
     */
151
    public function toggleSubscribeAreaStatusAction(
152
        Request $request,
153
        ZikulaHttpKernelInterface $kernel,
154
        TranslatorInterface $translator,
155
        PermissionApiInterface $permissionApi,
156
        HookCollectorInterface $collector,
157
        HookDispatcherInterface $dispatcher
158
    ): JsonResponse {
159
        $this->setTranslator($translator);
160
        if (!$this->isCsrfTokenValid('hook-ui', $request->request->get('token'))) {
161
            throw new AccessDeniedException();
162
        }
163
164
        // get subscriberarea from POST
165
        $subscriberArea = $request->request->get('subscriberarea', '');
166
        if (empty($subscriberArea)) {
167
            throw new InvalidArgumentException($this->trans('No subscriber area passed.'));
168
        }
169
170
        // get subscriber module based on area and do some checks
171
        $subscriber = $collector->getSubscriber($subscriberArea);
172
        if (null === $subscriber) {
173
            throw new InvalidArgumentException($this->trans('Module "%name%" is not a valid subscriber.', ['%name%' => $subscriber->getOwner()]));
174
        }
175
        if (!$kernel->isBundle($subscriber->getOwner())) {
176
            throw new RuntimeException($this->trans('Subscriber module "%name%" is not available.', ['%name%' => $subscriber->getOwner()]));
177
        }
178
        if (!$permissionApi->hasPermission($subscriber->getOwner() . '::', '::', ACCESS_ADMIN)) {
179
            throw new AccessDeniedException();
180
        }
181
182
        // get providerarea from POST
183
        $providerArea = $request->request->get('providerarea', '');
184
        if (empty($providerArea)) {
185
            throw new InvalidArgumentException($this->trans('No provider area passed.'));
186
        }
187
188
        // get provider module based on area and do some checks
189
        $provider = $collector->getProvider($providerArea);
190
        if (null === $provider) {
191
            throw new InvalidArgumentException($this->trans('Module "%name%" is not a valid provider.', ['%name%' => $provider->getOwner()]));
192
        }
193
        if (!$kernel->isBundle($provider->getOwner())) {
194
            throw new RuntimeException($this->trans('Provider module "%name%" is not available.', ['%name%' => $provider->getOwner()]));
195
        }
196
        if (!$permissionApi->hasPermission($provider->getOwner() . '::', '::', ACCESS_ADMIN)) {
197
            throw new AccessDeniedException();
198
        }
199
200
        // check if binding between areas exists
201
        $binding = $dispatcher->getBindingBetweenAreas($subscriberArea, $providerArea);
202
        if (!$binding) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $binding of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
203
            $dispatcher->bindSubscriber($subscriberArea, $providerArea);
204
        } else {
205
            $dispatcher->unbindSubscriber($subscriberArea, $providerArea);
206
        }
207
208
        // ajax response
209
        $response = [
210
            'result' => true,
211
            'action' => $binding ? 'unbind' : 'bind',
212
            'subscriberarea' => $subscriberArea,
213
            'subscriberarea_id' => md5($subscriberArea),
214
            'providerarea' => $providerArea,
215
            'providerarea_id' => md5($providerArea),
216
            'isSubscriberSelfCapable' => $collector->isCapable($subscriber->getOwner(), HookCollectorInterface::HOOK_SUBSCRIBE_OWN)
217
        ];
218
219
        return $this->json($response);
220
    }
221
222
    /**
223
     * @Route("/changeorder", methods = {"POST"}, options={"expose"=true})
224
     *
225
     * Changes the order of the providers' areas that are attached to a subscriber.
226
     *
227
     * @throws InvalidArgumentException Thrown if the subscriber or subscriberarea parameters aren't valid
228
     * @throws RuntimeException Thrown if the subscriber module isn't available
229
     * @throws AccessDeniedException Thrown if the user doesn't have admin access to the subscriber module
230
     */
231
    public function changeProviderAreaOrderAction(
232
        Request $request,
233
        ZikulaHttpKernelInterface $kernel,
234
        TranslatorInterface $translator,
235
        PermissionApiInterface $permissionApi,
236
        HookCollectorInterface $collector,
237
        HookDispatcherInterface $hookDispatcher
238
    ): JsonResponse {
239
        $this->setTranslator($translator);
240
        if (!$this->isCsrfTokenValid('hook-ui', $request->request->get('token'))) {
241
            throw new AccessDeniedException();
242
        }
243
244
        // get subscriberarea from POST
245
        $subscriberarea = $request->request->get('subscriberarea', '');
246
        if (empty($subscriberarea)) {
247
            throw new InvalidArgumentException($this->trans('No subscriber area passed.'));
248
        }
249
250
        // get subscriber module based on area and do some checks
251
        $subscriber = $collector->getSubscriber($subscriberarea);
252
        if (null === $subscriber) {
253
            throw new InvalidArgumentException($this->trans('Module "%name%" is not a valid subscriber.', ['%name%' => $subscriber->getOwner()]));
254
        }
255
        if (!$kernel->isBundle($subscriber->getOwner())) {
256
            throw new RuntimeException($this->trans('Subscriber module "%name%" is not available.', ['%name%' => $subscriber->getOwner()]));
257
        }
258
        if (!$permissionApi->hasPermission($subscriber->getOwner() . '::', '::', ACCESS_ADMIN)) {
259
            throw new AccessDeniedException();
260
        }
261
262
        // get providers' areas from POST
263
        $providerarea = $request->request->get('providerarea', '');
264
        if (!is_array($providerarea) || count($providerarea) < 1) {
265
            throw new InvalidArgumentException($this->trans('Providers\' areas order is not an array.'));
266
        }
267
268
        // set sorting
269
        $hookDispatcher->setBindOrder($subscriberarea, $providerarea);
270
271
        return $this->json(['result' => true]);
272
    }
273
}
274