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) { |
|
|
|
|
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
|
|
|
|
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.