1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link https://github.com/old-town/workflow-zf2-dispatch |
4
|
|
|
* @author Malofeykin Andrey <[email protected]> |
5
|
|
|
*/ |
6
|
|
|
namespace OldTown\Workflow\ZF2\Dispatch\RunParamsHandler; |
7
|
|
|
|
8
|
|
|
use Zend\EventManager\AbstractListenerAggregate; |
9
|
|
|
use Zend\EventManager\EventManagerAwareTrait; |
10
|
|
|
use Zend\EventManager\EventManagerInterface; |
11
|
|
|
use OldTown\Workflow\ZF2\Dispatch\Dispatcher\Dispatcher; |
12
|
|
|
use OldTown\Workflow\ZF2\Dispatch\Dispatcher\WorkflowDispatchEventInterface; |
13
|
|
|
use OldTown\Workflow\ZF2\Dispatch\Dispatcher\RunWorkflowParam; |
14
|
|
|
use OldTown\Workflow\ZF2\Dispatch\Metadata\ReaderInterface; |
15
|
|
|
use Zend\Mvc\Controller\AbstractController; |
16
|
|
|
use OldTown\Workflow\ZF2\Dispatch\Metadata\Target\RunParams\MetadataInterface; |
17
|
|
|
use OldTown\Workflow\ZF2\Dispatch\RunParamsHandler\RouteHandler\ResolveEntryIdEvent; |
18
|
|
|
use OldTown\Workflow\ZF2\Dispatch\RunParamsHandler\RouteHandler\ResolveEntryIdEventInterface; |
19
|
|
|
use ReflectionClass; |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Class RouteHandler |
24
|
|
|
* |
25
|
|
|
* @package OldTown\Workflow\ZF2\Dispatch\RunParamsHandler |
26
|
|
|
*/ |
27
|
|
|
class RouteHandler extends AbstractListenerAggregate |
28
|
|
|
{ |
29
|
|
|
use EventManagerAwareTrait; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Адаптер для чтения метаданных |
33
|
|
|
* |
34
|
|
|
* @var ReaderInterface |
35
|
|
|
*/ |
36
|
|
|
protected $metadataReader; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Имя класса событие, бросаемого когда требуется определить entryId |
40
|
|
|
* |
41
|
|
|
* @var string |
42
|
|
|
*/ |
43
|
|
|
protected $resolveEntryIdEventClassName = ResolveEntryIdEvent::class; |
44
|
|
|
|
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* RouteHandler constructor. |
48
|
|
|
* |
49
|
|
|
* @param array $options |
50
|
|
|
*/ |
51
|
|
|
public function __construct(array $options = []) |
52
|
|
|
{ |
53
|
|
|
$initOptions = [ |
54
|
|
|
array_key_exists('metadataReader', $options) ? $options['metadataReader'] : null |
55
|
|
|
]; |
56
|
|
|
call_user_func_array([$this, 'init'], $initOptions); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @param ReaderInterface $metadataReader |
61
|
|
|
*/ |
62
|
|
|
protected function init(ReaderInterface $metadataReader) |
63
|
|
|
{ |
64
|
|
|
$this->setMetadataReader($metadataReader); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @param EventManagerInterface $events |
69
|
|
|
*/ |
70
|
|
|
public function attach(EventManagerInterface $events) |
71
|
|
|
{ |
72
|
|
|
$events->getSharedManager()->attach(Dispatcher::class, WorkflowDispatchEventInterface::METADATA_WORKFLOW_TO_RUN_EVENT, [$this, 'onMetadataWorkflowToRun'], 80); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Получение метаданных для запуска workflow |
77
|
|
|
* |
78
|
|
|
* @param WorkflowDispatchEventInterface $e |
79
|
|
|
* |
80
|
|
|
* @return RunWorkflowParam |
81
|
|
|
* |
82
|
|
|
* @throws Exception\InvalidMetadataException |
83
|
|
|
* @throws Exception\ResolveEntryIdEventException |
84
|
|
|
*/ |
85
|
|
|
public function onMetadataWorkflowToRun(WorkflowDispatchEventInterface $e) |
86
|
|
|
{ |
87
|
|
|
$mvcEvent = $e->getMvcEvent(); |
88
|
|
|
$controller = $mvcEvent->getTarget(); |
89
|
|
|
if (!$controller instanceof AbstractController) { |
90
|
|
|
return null; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$routeMatch = $mvcEvent->getRouteMatch(); |
94
|
|
|
if (!$routeMatch) { |
95
|
|
|
return null; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$action = $routeMatch->getParam('action', 'not-found'); |
99
|
|
|
$actionMethod = AbstractController::getMethodFromAction($action); |
100
|
|
|
|
101
|
|
|
if (!method_exists($controller, $actionMethod)) { |
102
|
|
|
return null; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
$controllerClassName = get_class($controller); |
106
|
|
|
|
107
|
|
|
$metadata = $this->getMetadataReader()->loadMetadataForAction($controllerClassName, $actionMethod); |
108
|
|
|
|
109
|
|
View Code Duplication |
if (!$metadata instanceof MetadataInterface) { |
|
|
|
|
110
|
|
|
$errMsg = sprintf('Metadata not implement %s', MetadataInterface::class); |
111
|
|
|
throw new Exception\InvalidMetadataException($errMsg); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$workflowManagerNameParam = $metadata->getWorkflowManagerNameRouterParam(); |
115
|
|
|
$workflowManagerName = $routeMatch->getParam($workflowManagerNameParam, null); |
116
|
|
|
|
117
|
|
|
$workflowActionNameParam = $metadata->getWorkflowActionNameRouterParam(); |
118
|
|
|
$workflowActionName = $routeMatch->getParam($workflowActionNameParam, null); |
119
|
|
|
|
120
|
|
|
if (null === $workflowManagerName || null === $workflowActionName) { |
121
|
|
|
return null; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$runType = $e->getMetadata()->getWorkflowRunType(); |
125
|
|
|
|
126
|
|
|
$workflowNameParam = $metadata->getWorkflowNameRouterParam(); |
127
|
|
|
$workflowName = $routeMatch->getParam($workflowNameParam, null); |
128
|
|
|
|
129
|
|
|
|
130
|
|
|
|
131
|
|
|
$runWorkflowParam = new RunWorkflowParam(); |
132
|
|
|
$runWorkflowParam->setRunType($runType); |
133
|
|
|
$runWorkflowParam->setManagerName($workflowManagerName); |
134
|
|
|
$runWorkflowParam->setActionName($workflowActionName); |
135
|
|
|
|
136
|
|
|
if (RunWorkflowParam::WORKFLOW_RUN_INITIALIZE === $runType && null !== $workflowName) { |
137
|
|
|
$runWorkflowParam->setWorkflowName($workflowName); |
138
|
|
|
|
139
|
|
|
return $runWorkflowParam; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
|
143
|
|
|
if (RunWorkflowParam::WORKFLOW_RUN_TYPE_DO_ACTION === $runType && null === $workflowName) { |
144
|
|
|
$event = $this->resolveEntryIdEventFactory(); |
145
|
|
|
$resolveEntryIdResults = $this->getEventManager()->trigger(ResolveEntryIdEventInterface::RESOLVE_ENTRY_ID_EVENT, $event, function ($item) { |
146
|
|
|
return is_numeric($item); |
147
|
|
|
}); |
148
|
|
|
$resolveEntryIdResult = $resolveEntryIdResults->last(); |
149
|
|
|
|
150
|
|
|
if (is_numeric($resolveEntryIdResult)) { |
151
|
|
|
$runWorkflowParam->setEntryId($resolveEntryIdResult); |
152
|
|
|
|
153
|
|
|
return $runWorkflowParam; |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
|
158
|
|
|
return null; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Подписчики по умолчанию |
163
|
|
|
* |
164
|
|
|
* @return void |
165
|
|
|
*/ |
166
|
|
|
public function attachDefaultListeners() |
167
|
|
|
{ |
168
|
|
|
$this->getEventManager()->attach(ResolveEntryIdEventInterface::RESOLVE_ENTRY_ID_EVENT, [$this, 'onResolveEntryIdHandler']); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Определение entryId на основе параметров роута |
173
|
|
|
* |
174
|
|
|
* @param ResolveEntryIdEventInterface $event |
175
|
|
|
* |
176
|
|
|
* @return integer|null |
177
|
|
|
* |
178
|
|
|
* @throws Exception\InvalidMetadataException |
179
|
|
|
*/ |
180
|
|
|
public function onResolveEntryIdHandler(ResolveEntryIdEventInterface $event) |
181
|
|
|
{ |
182
|
|
|
$mvcEvent = $event->getWorkflowDispatchEvent()->getMvcEvent(); |
183
|
|
|
$controller = $mvcEvent->getTarget(); |
184
|
|
|
if (!$controller instanceof AbstractController) { |
185
|
|
|
return null; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$routeMatch = $mvcEvent->getRouteMatch(); |
189
|
|
|
if (!$routeMatch) { |
190
|
|
|
return null; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
$action = $routeMatch->getParam('action', 'not-found'); |
194
|
|
|
$actionMethod = AbstractController::getMethodFromAction($action); |
195
|
|
|
|
196
|
|
|
if (!method_exists($controller, $actionMethod)) { |
197
|
|
|
return null; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
$controllerClassName = get_class($controller); |
201
|
|
|
$metadata = $this->getMetadataReader()->loadMetadataForAction($controllerClassName, $actionMethod); |
202
|
|
|
|
203
|
|
View Code Duplication |
if (!$metadata instanceof MetadataInterface) { |
|
|
|
|
204
|
|
|
$errMsg = sprintf('Metadata not implement %s', MetadataInterface::class); |
205
|
|
|
throw new Exception\InvalidMetadataException($errMsg); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
$entryIdParam = $metadata->getEntryIdRouterParam(); |
209
|
|
|
return $routeMatch->getParam($entryIdParam, null); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* @return ReaderInterface |
215
|
|
|
*/ |
216
|
|
|
public function getMetadataReader() |
217
|
|
|
{ |
218
|
|
|
return $this->metadataReader; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* @param ReaderInterface $metadataReader |
223
|
|
|
* |
224
|
|
|
* @return $this |
225
|
|
|
*/ |
226
|
|
|
public function setMetadataReader(ReaderInterface $metadataReader) |
227
|
|
|
{ |
228
|
|
|
$this->metadataReader = $metadataReader; |
229
|
|
|
|
230
|
|
|
return $this; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* Имя класса событие, бросаемого когда требуется определить entryId |
235
|
|
|
* |
236
|
|
|
* @return string |
237
|
|
|
*/ |
238
|
|
|
public function getResolveEntryIdEventClassName() |
239
|
|
|
{ |
240
|
|
|
return $this->resolveEntryIdEventClassName; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Устанавливает имя класса событие, бросаемого когда требуется определить entryId |
245
|
|
|
* |
246
|
|
|
* @param string $resolveEntryIdEventClassName |
247
|
|
|
* |
248
|
|
|
* @return $this |
249
|
|
|
*/ |
250
|
|
|
public function setResolveEntryIdEventClassName($resolveEntryIdEventClassName) |
251
|
|
|
{ |
252
|
|
|
$this->resolveEntryIdEventClassName = $resolveEntryIdEventClassName; |
253
|
|
|
|
254
|
|
|
return $this; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Фабрика для создания объекта события бросаемого когда нужно определить значение entryId |
259
|
|
|
* |
260
|
|
|
* @return ResolveEntryIdEventInterface |
261
|
|
|
* |
262
|
|
|
* @throws Exception\ResolveEntryIdEventException |
263
|
|
|
*/ |
264
|
|
|
public function resolveEntryIdEventFactory() |
265
|
|
|
{ |
266
|
|
|
$className = $this->getResolveEntryIdEventClassName(); |
267
|
|
|
|
268
|
|
|
$r = new ReflectionClass($className); |
269
|
|
|
$event = $r->newInstance(); |
270
|
|
|
|
271
|
|
|
if (!$event instanceof ResolveEntryIdEventInterface) { |
272
|
|
|
$errMsg = sprintf('ResolveEntryIdEvent not implement %s', ResolveEntryIdEventInterface::class); |
273
|
|
|
throw new Exception\ResolveEntryIdEventException($errMsg); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
return $event; |
277
|
|
|
} |
278
|
|
|
} |
279
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.