|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* This file is part of the Zikula package. |
|
5
|
|
|
* |
|
6
|
|
|
* Copyright Zikula Foundation - http://zikula.org/ |
|
7
|
|
|
* |
|
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
9
|
|
|
* file that was distributed with this source code. |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine; |
|
13
|
|
|
|
|
14
|
|
|
use Doctrine\Common\Persistence\ObjectManager; |
|
15
|
|
|
use Doctrine\ORM\Query\Expr\OrderBy; |
|
16
|
|
|
use Symfony\Bridge\Doctrine\RegistryInterface; |
|
17
|
|
|
use Zikula\Bundle\HookBundle\Collector\HookCollectorInterface; |
|
18
|
|
|
use Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine\Entity\RepositoryInterface\HookBindingRepositoryInterface; |
|
19
|
|
|
use Zikula\Bundle\HookBundle\Dispatcher\Storage\Doctrine\Entity\RepositoryInterface\HookRuntimeRepositoryInterface; |
|
20
|
|
|
use Zikula\Bundle\HookBundle\Dispatcher\StorageInterface; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* Doctrine class. |
|
24
|
|
|
*/ |
|
25
|
|
|
class DoctrineStorage implements StorageInterface |
|
26
|
|
|
{ |
|
27
|
|
|
/** |
|
28
|
|
|
* @var Entity\HookRuntimeEntity[] |
|
29
|
|
|
*/ |
|
30
|
|
|
private $runtimeHandlers = []; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* @var ObjectManager |
|
34
|
|
|
*/ |
|
35
|
|
|
private $objectManager; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* @var HookBindingRepositoryInterface |
|
39
|
|
|
*/ |
|
40
|
|
|
private $hookBindingRepository; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @var HookRuntimeRepositoryInterface |
|
44
|
|
|
*/ |
|
45
|
|
|
private $hookRuntimeRepository; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* @var HookCollectorInterface |
|
49
|
|
|
*/ |
|
50
|
|
|
private $hookCollector; |
|
51
|
|
|
|
|
52
|
|
|
public function __construct( |
|
53
|
|
|
RegistryInterface $doctrine, |
|
54
|
|
|
HookBindingRepositoryInterface $hookBindingRepository, |
|
55
|
|
|
HookRuntimeRepositoryInterface $hookRuntimeRepository, |
|
56
|
|
|
HookCollectorInterface $hookCollector |
|
57
|
|
|
) { |
|
58
|
|
|
$this->objectManager = $doctrine->getManager(); |
|
59
|
|
|
$this->hookBindingRepository = $hookBindingRepository; |
|
60
|
|
|
$this->hookRuntimeRepository = $hookRuntimeRepository; |
|
61
|
|
|
$this->hookCollector = $hookCollector; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
|
|
65
|
|
|
private function generateRuntimeHandlers() |
|
66
|
|
|
{ |
|
67
|
|
|
// truncate runtime |
|
68
|
|
|
$this->hookRuntimeRepository->truncate(); |
|
69
|
|
|
|
|
70
|
|
|
$bindings = $this->hookBindingRepository->findBy([], ['sareaid' => 'ASC', 'sortorder' => 'ASC']); |
|
71
|
|
|
foreach ($bindings as $binding) { |
|
72
|
|
|
$this->addRuntimeHandlers($binding['sareaid'], $binding['pareaid']); |
|
73
|
|
|
} |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
private function addRuntimeHandlers($subscriberArea, $providerArea) |
|
77
|
|
|
{ |
|
78
|
|
|
$subscriberAreaObject = $this->hookCollector->getSubscriber($subscriberArea); |
|
79
|
|
|
$providerAreaObject = $this->hookCollector->getProvider($providerArea); |
|
80
|
|
|
$subscribers = $subscriberAreaObject->getEvents(); |
|
81
|
|
|
|
|
82
|
|
|
if (!$subscribers) { |
|
83
|
|
|
return false; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
foreach ($subscribers as $hookType => $eventName) { |
|
87
|
|
|
$types = $providerAreaObject->getProviderTypes(); |
|
88
|
|
|
if (isset($types[$hookType])) { |
|
89
|
|
|
$methods = is_array($types[$hookType]) ? $types[$hookType] : [$types[$hookType]]; |
|
90
|
|
|
foreach ($methods as $method) { |
|
91
|
|
|
$hookRuntimeEntity = new Entity\HookRuntimeEntity(); |
|
92
|
|
|
$hookRuntimeEntity->setSowner($subscriberAreaObject->getOwner()); |
|
93
|
|
|
$hookRuntimeEntity->setPowner($providerAreaObject->getOwner()); |
|
94
|
|
|
$hookRuntimeEntity->setSareaid($subscriberArea); |
|
95
|
|
|
$hookRuntimeEntity->setPareaid($providerArea); |
|
96
|
|
|
$hookRuntimeEntity->setEventname($eventName); |
|
97
|
|
|
$hookRuntimeEntity->setClassname(get_class($providerAreaObject)); |
|
98
|
|
|
$hookRuntimeEntity->setMethod($method); |
|
99
|
|
|
$hookRuntimeEntity->setServiceid($providerAreaObject->getServiceId()); |
|
100
|
|
|
$hookRuntimeEntity->setPriority(10); |
|
101
|
|
|
$this->objectManager->persist($hookRuntimeEntity); |
|
102
|
|
|
} |
|
103
|
|
|
} |
|
104
|
|
|
} |
|
105
|
|
|
$this->objectManager->flush(); |
|
106
|
|
|
|
|
107
|
|
|
return true; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
public function bindSubscriber($subscriberArea, $providerArea) |
|
111
|
|
|
{ |
|
112
|
|
|
$sa = $this->hookCollector->getSubscriber($subscriberArea); |
|
113
|
|
|
$pa = $this->hookCollector->getProvider($providerArea); |
|
114
|
|
|
|
|
115
|
|
|
$binding = new Entity\HookBindingEntity(); |
|
116
|
|
|
$binding->setSowner($sa->getOwner()); |
|
117
|
|
|
$binding->setPowner($pa->getOwner()); |
|
118
|
|
|
$binding->setSareaid($subscriberArea); |
|
119
|
|
|
$binding->setPareaid($providerArea); |
|
120
|
|
|
$binding->setCategory($sa->getCategory()); |
|
121
|
|
|
$binding->setSortorder(999); |
|
122
|
|
|
$this->objectManager->persist($binding); |
|
123
|
|
|
$this->objectManager->flush(); |
|
124
|
|
|
|
|
125
|
|
|
$this->generateRuntimeHandlers(); |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
public function unbindSubscriber($subscriberArea, $providerArea) |
|
129
|
|
|
{ |
|
130
|
|
|
$this->hookBindingRepository->deleteByBothAreas($subscriberArea, $providerArea); |
|
131
|
|
|
$this->generateRuntimeHandlers(); |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
/** |
|
135
|
|
|
* @param $areaName |
|
136
|
|
|
* @param string $type |
|
137
|
|
|
* @return array |
|
138
|
|
|
*/ |
|
139
|
|
|
public function getBindingsFor($areaName, $type = 'subscriber') |
|
140
|
|
|
{ |
|
141
|
|
|
$type = in_array($type, ['subscriber', 'provider']) ? $type : 'subscriber'; // validate field |
|
142
|
|
|
$area = $this->hookCollector->getSubscriber($areaName); |
|
143
|
|
|
|
|
144
|
|
|
if (!isset($area)) { |
|
145
|
|
|
return []; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
$order = new OrderBy(); |
|
149
|
|
|
$order->add('t.sortorder', 'ASC'); |
|
150
|
|
|
$order->add('t.sareaid', 'ASC'); |
|
151
|
|
|
$fieldMap = ['subscriber' => 'sareaid', 'provider' => 'pareaid']; |
|
152
|
|
|
$results = $this->hookBindingRepository->selectByAreaName($areaName, $fieldMap[$type]); |
|
153
|
|
|
|
|
154
|
|
|
$areas = []; |
|
155
|
|
|
foreach ($results as $result) { |
|
156
|
|
|
$area = $this->hookCollector->getProvider($result['pareaid']); |
|
157
|
|
|
$areas[] = [ |
|
158
|
|
|
'areaname' => $result['pareaid'], |
|
159
|
|
|
'category' => $area->getCategory() |
|
160
|
|
|
]; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
return $areas; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/** |
|
167
|
|
|
* sort bindings in order of appearance from $providerAreaIds |
|
168
|
|
|
* @param string $subscriberAreaName |
|
169
|
|
|
* @param array $providerAreaNames |
|
170
|
|
|
*/ |
|
171
|
|
|
public function setBindOrder($subscriberAreaName, array $providerAreaNames) |
|
172
|
|
|
{ |
|
173
|
|
|
$counter = 1; |
|
174
|
|
|
foreach ($providerAreaNames as $providerAreaName) { |
|
175
|
|
|
$this->hookBindingRepository->setSortOrder($counter, $subscriberAreaName, $providerAreaName); |
|
176
|
|
|
$counter++; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
$this->generateRuntimeHandlers(); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
public function getRuntimeMetaByEventName($eventName) |
|
183
|
|
|
{ |
|
184
|
|
|
if (!isset($this->runtimeHandlers[$eventName])) { |
|
185
|
|
|
$this->runtimeHandlers[$eventName] = $this->hookRuntimeRepository->getOneOrNullByEventName($eventName); |
|
186
|
|
|
} |
|
187
|
|
|
if ($this->runtimeHandlers[$eventName]) { |
|
188
|
|
|
return [ |
|
189
|
|
|
'areaid' => $this->runtimeHandlers[$eventName]->getSareaid(), |
|
190
|
|
|
'owner' => $this->runtimeHandlers[$eventName]->getSowner() |
|
191
|
|
|
]; |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
return false; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
public function getBindingBetweenAreas($subscriberArea, $providerArea) |
|
198
|
|
|
{ |
|
199
|
|
|
return $this->hookBindingRepository->findOneOrNullByAreas($subscriberArea, $providerArea); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
/** |
|
203
|
|
|
* binding between hook areas should be allowed if: |
|
204
|
|
|
* 1. *Category* is the same for both |
|
205
|
|
|
* 2. the provider and subscriber have implemented at least one of same *hookType* |
|
206
|
|
|
* @param $subscriberArea |
|
207
|
|
|
* @param $providerArea |
|
208
|
|
|
* @return bool |
|
209
|
|
|
*/ |
|
210
|
|
|
public function isAllowedBindingBetweenAreas($subscriberArea, $providerArea) |
|
211
|
|
|
{ |
|
212
|
|
|
if ($this->hookCollector->hasSubscriber($subscriberArea)) { |
|
213
|
|
|
$subscriberTypes = $this->hookCollector->getSubscriber($subscriberArea)->getEvents(); // array('hookType' => 'eventName') |
|
|
|
|
|
|
214
|
|
|
$subscriberTypes = array_keys($subscriberTypes); |
|
215
|
|
|
$subscriberCategory = $this->hookCollector->getSubscriber($subscriberArea)->getCategory(); |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
if (empty($subscriberTypes)) { |
|
219
|
|
|
return false; |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
foreach ($subscriberTypes as $subscriberType) { |
|
223
|
|
|
if ($this->hookCollector->hasProvider($providerArea)) { |
|
224
|
|
|
$providerTypes = $this->hookCollector->getProvider($providerArea)->getProviderTypes(); |
|
225
|
|
|
$providerCategory = $this->hookCollector->getProvider($providerArea)->getCategory(); |
|
226
|
|
|
foreach (array_keys($providerTypes) as $providerType) { |
|
227
|
|
|
if ($subscriberCategory == $providerCategory && $subscriberType == $providerType) { |
|
|
|
|
|
|
228
|
|
|
return true; |
|
229
|
|
|
} |
|
230
|
|
|
} |
|
231
|
|
|
} |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
return false; |
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
|
public function getBindingsBetweenOwners($subscriberOwner, $providerOwner) |
|
238
|
|
|
{ |
|
239
|
|
|
return $this->hookBindingRepository->findByOwners($subscriberOwner, $providerOwner); |
|
240
|
|
|
} |
|
241
|
|
|
} |
|
242
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.