1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link https://github.com/old-town/old-town-workflow |
4
|
|
|
* @author Malofeykin Andrey <[email protected]> |
5
|
|
|
*/ |
6
|
|
|
namespace OldTown\Workflow\Spi\Memory; |
7
|
|
|
|
8
|
|
|
use OldTown\PropertySet\PropertySetInterface; |
9
|
|
|
use OldTown\PropertySet\PropertySetManager; |
10
|
|
|
use OldTown\Workflow\Exception\ArgumentNotNumericException; |
11
|
|
|
use OldTown\Workflow\Exception\InvalidWorkflowEntryException; |
12
|
|
|
use OldTown\Workflow\Exception\NotFoundWorkflowEntryException; |
13
|
|
|
use OldTown\Workflow\Query\FieldExpression; |
14
|
|
|
use OldTown\Workflow\Query\NestedExpression; |
15
|
|
|
use OldTown\Workflow\Query\WorkflowExpressionQuery; |
16
|
|
|
use OldTown\Workflow\Spi\SimpleStep; |
17
|
|
|
use OldTown\Workflow\Spi\SimpleWorkflowEntry; |
18
|
|
|
use OldTown\Workflow\Spi\StepInterface; |
19
|
|
|
use OldTown\Workflow\Spi\WorkflowEntryInterface; |
20
|
|
|
use OldTown\Workflow\Exception\StoreException; |
21
|
|
|
use DateTime; |
22
|
|
|
use OldTown\Workflow\Spi\WorkflowStoreInterface; |
23
|
|
|
use SplObjectStorage; |
24
|
|
|
use OldTown\Workflow\Exception\InvalidArgumentException; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Class MemoryWorkflowStore |
28
|
|
|
* |
29
|
|
|
* @package OldTown\Workflow\Spi\Memory |
30
|
|
|
*/ |
31
|
|
|
class MemoryWorkflowStore implements WorkflowStoreInterface |
32
|
|
|
{ |
33
|
|
|
/** |
34
|
|
|
* @var SimpleWorkflowEntry[] |
35
|
|
|
*/ |
36
|
|
|
protected static $entryCache = []; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var SplObjectStorage[]|SimpleStep[] |
40
|
|
|
*/ |
41
|
|
|
protected static $currentStepsCache = []; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var SplObjectStorage[]|SimpleStep[] |
45
|
|
|
*/ |
46
|
|
|
protected static $historyStepsCache = []; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var array |
50
|
|
|
*/ |
51
|
|
|
protected static $propertySetCache = []; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var int |
55
|
|
|
*/ |
56
|
|
|
protected static $globalEntryId = 1; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var int |
60
|
|
|
*/ |
61
|
|
|
protected static $globalStepId = 1; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Вызывается один раз, при инициализации хранилища |
65
|
|
|
* |
66
|
|
|
* @param array $props |
67
|
|
|
* @throws StoreException |
68
|
|
|
*/ |
69
|
20 |
|
public function init(array $props = []) |
70
|
|
|
{ |
71
|
|
|
// TODO: Implement init() method. |
72
|
20 |
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Возвращает PropertySet that связанный с данным экземпляром workflow |
76
|
|
|
* @param integer $entryId id workflow |
77
|
|
|
* @return PropertySetInterface |
78
|
|
|
* @throws StoreException |
79
|
|
|
* @throws \OldTown\PropertySet\Exception\RuntimeException |
80
|
|
|
* @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
81
|
|
|
*/ |
82
|
22 |
View Code Duplication |
public function getPropertySet($entryId) |
|
|
|
|
83
|
|
|
{ |
84
|
22 |
|
if (array_key_exists($entryId, static::$propertySetCache)) { |
85
|
17 |
|
return static::$propertySetCache[$entryId]; |
86
|
|
|
} |
87
|
|
|
|
88
|
21 |
|
if (!is_numeric($entryId)) { |
89
|
1 |
|
$errMsg = sprintf('Аргумент должен быть числом. Актуальное значение %s', $entryId); |
90
|
1 |
|
throw new ArgumentNotNumericException($errMsg); |
91
|
|
|
} |
92
|
20 |
|
$entryId = (integer)$entryId; |
93
|
|
|
|
94
|
20 |
|
$ps = $this->createPropertySet(); |
95
|
20 |
|
static::$propertySetCache[$entryId] = $ps; |
96
|
|
|
|
97
|
20 |
|
return static::$propertySetCache[$entryId]; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Создаем экземпляр PropertySet |
102
|
|
|
* |
103
|
|
|
* @return PropertySetInterface |
104
|
|
|
*/ |
105
|
19 |
|
protected function createPropertySet() |
106
|
|
|
{ |
107
|
19 |
|
return PropertySetManager::getInstance('memory'); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
//~ Methods //////////////////////////////////////////////////////////////// |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Устанавливает статус для сущности workflow с заданным id |
114
|
|
|
* |
115
|
|
|
* @param int $entryId |
116
|
|
|
* @param int $state |
117
|
|
|
* |
118
|
|
|
* @return $this |
119
|
|
|
* @throws StoreException |
120
|
|
|
* @throws NotFoundWorkflowEntryException |
121
|
|
|
* @throws ArgumentNotNumericException |
122
|
|
|
* @throws InvalidWorkflowEntryException |
123
|
|
|
*/ |
124
|
17 |
|
public function setEntryState($entryId, $state) |
125
|
|
|
{ |
126
|
|
|
/** @var SimpleWorkflowEntry $theEntry */ |
127
|
17 |
|
$theEntry = $this->findEntry($entryId); |
128
|
17 |
|
$theEntry->setState($state); |
129
|
17 |
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Ищет сущность workflow с заданным id во внутреннем кеше |
133
|
|
|
* |
134
|
|
|
* @param int $entryId |
135
|
|
|
* |
136
|
|
|
* @return WorkflowEntryInterface |
137
|
|
|
* @throws NotFoundWorkflowEntryException |
138
|
|
|
* @throws ArgumentNotNumericException |
139
|
|
|
* @throws InvalidWorkflowEntryException |
140
|
|
|
*/ |
141
|
20 |
|
public function findEntry($entryId) |
142
|
|
|
{ |
143
|
20 |
|
if (!is_numeric($entryId)) { |
144
|
1 |
|
$errMsg = sprintf('Аргумент должен быть числом. Актуальное значение %s', $entryId); |
145
|
1 |
|
throw new ArgumentNotNumericException($errMsg); |
146
|
|
|
} |
147
|
|
|
|
148
|
19 |
|
if (!array_key_exists($entryId, static::$entryCache)) { |
149
|
1 |
|
$errMsg = sprintf('Не найдена сущность workflow с id %s', $entryId); |
150
|
1 |
|
throw new NotFoundWorkflowEntryException($errMsg); |
151
|
|
|
} |
152
|
|
|
|
153
|
18 |
|
$entry = static::$entryCache[$entryId]; |
154
|
|
|
|
155
|
18 |
|
if (!$entry instanceof WorkflowEntryInterface) { |
156
|
1 |
|
$errMsg = sprintf('Сущность workflow должна реализовывать интерфейс %s', WorkflowEntryInterface::class); |
157
|
1 |
|
throw new InvalidWorkflowEntryException($errMsg); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
|
161
|
17 |
|
return $entry; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Создает экземпляр workflow |
166
|
|
|
* |
167
|
|
|
* @param string $workflowName |
168
|
|
|
* |
169
|
|
|
* @return SimpleWorkflowEntry |
170
|
|
|
*/ |
171
|
32 |
|
public function createEntry($workflowName) |
172
|
|
|
{ |
173
|
32 |
|
$id = static::$globalEntryId++; |
174
|
32 |
|
$entry = new SimpleWorkflowEntry($id, $workflowName, WorkflowEntryInterface::CREATED); |
175
|
32 |
|
static::$entryCache[$id] = $entry; |
176
|
|
|
|
177
|
32 |
|
return $entry; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Создает новый шаг |
182
|
|
|
* |
183
|
|
|
* @param integer $entryId |
184
|
|
|
* @param integer $stepId |
185
|
|
|
* @param string $owner |
186
|
|
|
* @param DateTime $startDate |
187
|
|
|
* @param DateTime $dueDate |
188
|
|
|
* @param string $status |
189
|
|
|
* @param array $previousIds |
190
|
|
|
* |
191
|
|
|
* @return SimpleStep |
192
|
|
|
*/ |
193
|
20 |
|
public function createCurrentStep($entryId, $stepId, $owner = null, DateTime $startDate, DateTime $dueDate = null, $status, array $previousIds = []) |
194
|
|
|
{ |
195
|
20 |
|
$id = static::$globalStepId++; |
196
|
20 |
|
$step = new SimpleStep($id, $entryId, $stepId, 0, $owner, $startDate, $dueDate, null, $status, $previousIds, null); |
197
|
|
|
|
198
|
20 |
|
if (!array_key_exists($entryId, static::$currentStepsCache)) { |
199
|
20 |
|
$currentSteps = new SplObjectStorage(); |
200
|
20 |
|
static::$currentStepsCache[$entryId] = $currentSteps; |
201
|
20 |
|
} |
202
|
|
|
|
203
|
|
|
|
204
|
20 |
|
static::$currentStepsCache[$entryId]->attach($step); |
|
|
|
|
205
|
|
|
|
206
|
20 |
|
return $step; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Ищет текущий набор шагов для сущности workflow c заданным id |
211
|
|
|
* |
212
|
|
|
* @param Integer $entryId |
213
|
|
|
* |
214
|
|
|
* @return SimpleStep[]|SplObjectStorage |
215
|
|
|
* @throws ArgumentNotNumericException |
216
|
|
|
*/ |
217
|
21 |
View Code Duplication |
public function findCurrentSteps($entryId) |
|
|
|
|
218
|
|
|
{ |
219
|
21 |
|
if (!is_numeric($entryId)) { |
220
|
1 |
|
$errMsg = sprintf('Аргумент должен быть числом. Актуальное значение %s', $entryId); |
221
|
1 |
|
throw new ArgumentNotNumericException($errMsg); |
222
|
|
|
} |
223
|
20 |
|
$entryId = (integer)$entryId; |
224
|
|
|
|
225
|
20 |
|
if (!array_key_exists($entryId, static::$currentStepsCache)) { |
226
|
3 |
|
$currentSteps = new SplObjectStorage(); |
227
|
3 |
|
static::$currentStepsCache[$entryId] = $currentSteps; |
228
|
3 |
|
} |
229
|
|
|
|
230
|
20 |
|
return static::$currentStepsCache[$entryId]; |
|
|
|
|
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* Пометить текущий шаг как выполненный |
235
|
|
|
* |
236
|
|
|
* @param StepInterface $step |
237
|
|
|
* @param integer $actionId |
238
|
|
|
* @param DateTime $finishDate |
239
|
|
|
* @param string $status |
240
|
|
|
* @param string $caller |
241
|
|
|
* |
242
|
|
|
* @return null|SimpleStep |
243
|
|
|
* |
244
|
|
|
* @throws ArgumentNotNumericException |
245
|
|
|
*/ |
246
|
8 |
|
public function markFinished(StepInterface $step, $actionId, DateTime $finishDate, $status, $caller) |
247
|
|
|
{ |
248
|
8 |
|
$entryId = $step->getEntryId(); |
249
|
8 |
|
$currentSteps = $this->findCurrentSteps($entryId); |
250
|
|
|
|
251
|
8 |
|
foreach ($currentSteps as $theStep) { |
|
|
|
|
252
|
7 |
|
if ($theStep->getId() === $step->getId()) { |
253
|
7 |
|
$theStep->setStatus($status); |
254
|
7 |
|
$theStep->setActionId($actionId); |
255
|
7 |
|
$theStep->setFinishDate($finishDate); |
256
|
7 |
|
$theStep->setCaller($caller); |
257
|
|
|
|
258
|
7 |
|
return $theStep; |
259
|
|
|
} |
260
|
1 |
|
} |
261
|
|
|
|
262
|
1 |
|
return null; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Сбрасывает внутренние кеш хранилища. |
267
|
|
|
*/ |
268
|
34 |
|
public static function reset() |
269
|
|
|
{ |
270
|
34 |
|
static::$entryCache = []; |
271
|
34 |
|
static::$currentStepsCache = []; |
272
|
34 |
|
static::$historyStepsCache = []; |
273
|
34 |
|
static::$propertySetCache = []; |
274
|
34 |
|
static::$globalEntryId = 1; |
275
|
34 |
|
static::$globalStepId = 1; |
276
|
34 |
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Перенос шага в историю |
280
|
|
|
* |
281
|
|
|
* @param StepInterface $step |
282
|
|
|
* |
283
|
|
|
* @return void |
284
|
|
|
* |
285
|
|
|
* @throws \OldTown\Workflow\Exception\ArgumentNotNumericException |
286
|
|
|
*/ |
287
|
8 |
|
public function moveToHistory(StepInterface $step) |
288
|
|
|
{ |
289
|
8 |
|
$entryId = $step->getEntryId(); |
290
|
8 |
|
$currentSteps = $this->findCurrentSteps($entryId); |
291
|
|
|
|
292
|
8 |
|
if (!array_key_exists($entryId, static::$historyStepsCache)) { |
293
|
7 |
|
$historySteps = new SplObjectStorage(); |
294
|
7 |
|
static::$historyStepsCache[$entryId] = $historySteps; |
295
|
7 |
|
} |
296
|
|
|
|
297
|
8 |
|
foreach ($currentSteps as $currentStep) { |
|
|
|
|
298
|
7 |
|
if ($step->getId() === $currentStep->getId()) { |
299
|
7 |
|
$currentSteps->detach($currentStep); |
|
|
|
|
300
|
7 |
|
foreach (static::$historyStepsCache[$entryId] as $historyStep) { |
|
|
|
|
301
|
|
|
/** @var StepInterface $historyStep */ |
302
|
1 |
|
if ($historyStep->getId() === $step->getId()) { |
303
|
1 |
|
static::$historyStepsCache[$entryId]->detach($historyStep); |
304
|
1 |
|
} |
305
|
7 |
|
} |
306
|
|
|
|
307
|
7 |
|
static::$historyStepsCache[$entryId]->attach($currentStep); |
|
|
|
|
308
|
|
|
|
309
|
7 |
|
break; |
310
|
|
|
} |
311
|
8 |
|
} |
312
|
8 |
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Поиск по истории шагов |
316
|
|
|
* |
317
|
|
|
* @param $entryId |
318
|
|
|
* |
319
|
|
|
* @return SimpleStep[]|SplObjectStorage |
320
|
|
|
*/ |
321
|
2 |
|
public function findHistorySteps($entryId) |
322
|
|
|
{ |
323
|
2 |
|
if (array_key_exists($entryId, static::$historyStepsCache)) { |
324
|
1 |
|
return static::$historyStepsCache[$entryId]; |
|
|
|
|
325
|
|
|
} |
326
|
|
|
|
327
|
1 |
|
return new SplObjectStorage(); |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Поиск в хранилище |
332
|
|
|
* |
333
|
|
|
* @param WorkflowExpressionQuery $query |
334
|
|
|
* |
335
|
|
|
* @return array |
336
|
|
|
* |
337
|
|
|
* @throws \OldTown\Workflow\Exception\InvalidArgumentException |
338
|
|
|
*/ |
339
|
13 |
|
public function query(WorkflowExpressionQuery $query) |
340
|
|
|
{ |
341
|
13 |
|
$results = []; |
342
|
|
|
|
343
|
13 |
|
foreach (static::$entryCache as $entryId => $mapEntry) { |
344
|
12 |
|
if ($this->queryInternal($entryId, $query)) { |
345
|
5 |
|
$results[$entryId] = $entryId; |
346
|
5 |
|
} |
347
|
7 |
|
} |
348
|
|
|
|
349
|
7 |
|
return $results; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Реализация поиска в харинилище |
354
|
|
|
* |
355
|
|
|
* @param integer $entryId |
356
|
|
|
* @param WorkflowExpressionQuery $query |
357
|
|
|
* |
358
|
|
|
* @return bool |
359
|
|
|
* |
360
|
|
|
* @throws \OldTown\Workflow\Exception\InvalidArgumentException |
361
|
|
|
*/ |
362
|
12 |
|
protected function queryInternal($entryId, WorkflowExpressionQuery $query) |
363
|
|
|
{ |
364
|
12 |
|
$expression = $query->getExpression(); |
365
|
|
|
|
366
|
12 |
|
if ($expression->isNested()) { |
367
|
3 |
|
return $this->checkNestedExpression($entryId, $expression); |
|
|
|
|
368
|
|
|
} else { |
369
|
9 |
|
return $this->checkExpression($entryId, $expression); |
|
|
|
|
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
// |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* Проверка выражения |
377
|
|
|
* |
378
|
|
|
* @param integer $entryId |
379
|
|
|
* @param FieldExpression $expression |
380
|
|
|
* |
381
|
|
|
* @return bool |
382
|
|
|
* |
383
|
|
|
* @throws InvalidArgumentException |
384
|
|
|
*/ |
385
|
12 |
|
private function checkExpression($entryId, FieldExpression $expression) |
386
|
|
|
{ |
387
|
12 |
|
$value = $expression->getValue(); |
388
|
12 |
|
$operator = $expression->getOperator(); |
389
|
12 |
|
$field = $expression->getField(); |
390
|
12 |
|
$context = $expression->getContext(); |
391
|
|
|
|
392
|
12 |
|
$id = (integer)$entryId; |
393
|
|
|
|
394
|
12 |
|
if ($context === FieldExpression::ENTRY) { |
395
|
9 |
|
$theEntry = static::$entryCache[$id]; |
396
|
|
|
|
397
|
9 |
|
if ($field === FieldExpression::NAME) { |
398
|
3 |
|
return $this->compareText($theEntry->getWorkflowName(), $value, $operator); |
399
|
|
|
} |
400
|
|
|
|
401
|
7 |
|
if ($field === FieldExpression::STATE) { |
402
|
6 |
|
if (!is_numeric($value)) { |
403
|
1 |
|
$errMsg = 'unknown field'; |
404
|
1 |
|
throw new InvalidArgumentException($errMsg); |
405
|
|
|
} |
406
|
|
|
|
407
|
5 |
|
$valueInt = (integer)$value; |
408
|
|
|
|
409
|
5 |
|
return $this->compareLong($valueInt, $theEntry->getState(), $operator); |
410
|
|
|
} |
411
|
|
|
|
412
|
1 |
|
$errMsg = 'unknown field'; |
413
|
1 |
|
throw new InvalidArgumentException($errMsg); |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
/** @var SplObjectStorage[]|SimpleStep[] $steps */ |
417
|
3 |
|
$steps = []; |
418
|
|
|
|
419
|
3 |
|
if ($context === FieldExpression::CURRENT_STEPS) { |
420
|
1 |
|
$steps = array_key_exists($id, static::$currentStepsCache) ? static::$currentStepsCache[$id] : $steps; |
421
|
3 |
|
} elseif ($context === FieldExpression::HISTORY_STEPS) { |
422
|
1 |
|
$steps = array_key_exists($id, static::$historyStepsCache) ? static::$historyStepsCache[$id] : $steps; |
423
|
1 |
|
} else { |
424
|
1 |
|
$errMsg = 'unknown field context'; |
425
|
1 |
|
throw new InvalidArgumentException($errMsg); |
426
|
|
|
} |
427
|
|
|
|
428
|
2 |
|
if (0 === count($steps)) { |
429
|
2 |
|
return false; |
430
|
|
|
} |
431
|
|
|
|
432
|
2 |
|
$expressionResult = false; |
433
|
|
|
|
434
|
|
|
switch ($field) { |
435
|
2 |
View Code Duplication |
case FieldExpression::ACTION: |
|
|
|
|
436
|
1 |
|
if (!is_numeric($value)) { |
437
|
1 |
|
$errMsg = 'unknown field'; |
438
|
1 |
|
throw new InvalidArgumentException($errMsg); |
439
|
|
|
} |
440
|
|
|
|
441
|
1 |
|
$actionId = (integer)$value; |
442
|
|
|
|
443
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
444
|
1 |
|
if ($this->compareLong($step->getActionId(), $actionId, $operator)) { |
445
|
1 |
|
$expressionResult = true; |
446
|
|
|
|
447
|
1 |
|
break; |
448
|
|
|
} |
449
|
1 |
|
} |
450
|
|
|
|
451
|
|
|
|
452
|
1 |
|
break; |
453
|
|
|
|
454
|
2 |
View Code Duplication |
case FieldExpression::CALLER: |
|
|
|
|
455
|
1 |
|
$caller = $value; |
456
|
1 |
|
if ('string' !== gettype($caller)) { |
457
|
1 |
|
$errMsg = 'unknown field'; |
458
|
1 |
|
throw new InvalidArgumentException($errMsg); |
459
|
|
|
} |
460
|
|
|
|
461
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
462
|
1 |
|
if ($this->compareText($step->getCaller(), $caller, $operator)) { |
463
|
1 |
|
$expressionResult = true; |
464
|
|
|
|
465
|
1 |
|
break; |
466
|
|
|
} |
467
|
1 |
|
} |
468
|
|
|
|
469
|
1 |
|
break; |
470
|
|
|
|
471
|
2 |
View Code Duplication |
case FieldExpression::FINISH_DATE: |
|
|
|
|
472
|
1 |
|
if ($value instanceof DateTime) { |
473
|
1 |
|
$finishDate = $value; |
474
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
475
|
1 |
|
if ($this->compareDate($step->getFinishDate(), $finishDate, $operator)) { |
476
|
1 |
|
$expressionResult = true; |
477
|
|
|
|
478
|
1 |
|
break; |
479
|
|
|
} |
480
|
1 |
|
} |
481
|
1 |
|
} else { |
482
|
1 |
|
$errMsg = 'unknown field'; |
483
|
1 |
|
throw new InvalidArgumentException($errMsg); |
484
|
|
|
} |
485
|
|
|
|
486
|
1 |
|
break; |
487
|
|
|
|
488
|
1 |
View Code Duplication |
case FieldExpression::OWNER: |
|
|
|
|
489
|
1 |
|
$owner = $value; |
490
|
1 |
|
if ('string' !== gettype($owner)) { |
491
|
1 |
|
$errMsg = 'unknown field'; |
492
|
1 |
|
throw new InvalidArgumentException($errMsg); |
493
|
|
|
} |
494
|
|
|
|
495
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
496
|
1 |
|
if ($this->compareText($step->getOwner(), $owner, $operator)) { |
497
|
1 |
|
$expressionResult = true; |
498
|
|
|
|
499
|
1 |
|
break; |
500
|
|
|
} |
501
|
1 |
|
} |
502
|
|
|
|
503
|
|
|
|
504
|
1 |
|
break; |
505
|
|
|
|
506
|
1 |
View Code Duplication |
case FieldExpression::START_DATE: |
|
|
|
|
507
|
1 |
|
if ($value instanceof DateTime) { |
508
|
1 |
|
$startDate = $value; |
509
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
510
|
1 |
|
if ($this->compareDate($step->getStartDate(), $startDate, $operator)) { |
511
|
1 |
|
$expressionResult = true; |
512
|
|
|
|
513
|
1 |
|
break; |
514
|
|
|
} |
515
|
1 |
|
} |
516
|
1 |
|
} else { |
517
|
1 |
|
$errMsg = 'unknown field'; |
518
|
1 |
|
throw new InvalidArgumentException($errMsg); |
519
|
|
|
} |
520
|
|
|
|
521
|
1 |
|
break; |
522
|
|
|
|
523
|
1 |
View Code Duplication |
case FieldExpression::STEP: |
|
|
|
|
524
|
1 |
|
if (!is_numeric($value)) { |
525
|
1 |
|
$errMsg = 'unknown field'; |
526
|
1 |
|
throw new InvalidArgumentException($errMsg); |
527
|
|
|
} |
528
|
1 |
|
$stepId = (integer)$value; |
529
|
|
|
|
530
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
531
|
1 |
|
if ($this->compareLong($step->getStepId(), $stepId, $operator)) { |
532
|
1 |
|
$expressionResult = true; |
533
|
|
|
|
534
|
1 |
|
break; |
535
|
|
|
} |
536
|
1 |
|
} |
537
|
|
|
|
538
|
1 |
|
break; |
539
|
|
|
|
540
|
1 |
View Code Duplication |
case FieldExpression::STATUS: |
|
|
|
|
541
|
1 |
|
$status = $value; |
542
|
1 |
|
if ('string' !== gettype($status)) { |
543
|
1 |
|
$errMsg = 'unknown field'; |
544
|
1 |
|
throw new InvalidArgumentException($errMsg); |
545
|
|
|
} |
546
|
|
|
|
547
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
548
|
1 |
|
if ($this->compareText($step->getStatus(), $status, $operator)) { |
549
|
1 |
|
$expressionResult = true; |
550
|
|
|
|
551
|
1 |
|
break; |
552
|
|
|
} |
553
|
1 |
|
} |
554
|
|
|
|
555
|
1 |
|
break; |
556
|
|
|
|
557
|
1 |
View Code Duplication |
case FieldExpression::DUE_DATE: |
|
|
|
|
558
|
1 |
|
if ($value instanceof DateTime) { |
559
|
1 |
|
$dueDate = $value; |
560
|
1 |
|
foreach ($steps as $step) { |
|
|
|
|
561
|
1 |
|
if ($this->compareDate($step->getDueDate(), $dueDate, $operator)) { |
562
|
1 |
|
$expressionResult = true; |
563
|
|
|
|
564
|
1 |
|
break; |
565
|
|
|
} |
566
|
1 |
|
} |
567
|
1 |
|
} else { |
568
|
1 |
|
$errMsg = 'unknown field'; |
569
|
1 |
|
throw new InvalidArgumentException($errMsg); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
|
573
|
1 |
|
break; |
574
|
|
|
} |
575
|
|
|
|
576
|
2 |
|
if ($expression->isNegate()) { |
577
|
1 |
|
return !$expressionResult; |
578
|
|
|
} else { |
579
|
2 |
|
return $expressionResult; |
580
|
|
|
} |
581
|
|
|
} |
582
|
|
|
|
583
|
|
|
/** |
584
|
|
|
* Проверка вложенных выражений |
585
|
|
|
* |
586
|
|
|
* @param integer $entryId |
587
|
|
|
* @param NestedExpression $nestedExpression |
588
|
|
|
* |
589
|
|
|
* @return bool |
590
|
|
|
* @throws InvalidArgumentException |
591
|
|
|
*/ |
592
|
3 |
|
private function checkNestedExpression($entryId, NestedExpression $nestedExpression) |
593
|
|
|
{ |
594
|
3 |
|
$expressions = $nestedExpression->getExpressions(); |
595
|
3 |
|
foreach ($expressions as $expression) { |
596
|
3 |
|
if ($expression->isNested()) { |
597
|
1 |
|
$expressionResult = $this->checkNestedExpression($entryId, $expression); |
|
|
|
|
598
|
1 |
|
} else { |
599
|
3 |
|
$expressionResult = $this->checkExpression($entryId, $expression); |
|
|
|
|
600
|
|
|
} |
601
|
|
|
|
602
|
3 |
|
if (false === $expressionResult && $nestedExpression->getExpressionOperator() === NestedExpression::AND_OPERATOR) { |
603
|
1 |
|
return $nestedExpression->isNegate(); |
604
|
|
|
} |
605
|
3 |
|
if (true === $expressionResult && $nestedExpression->getExpressionOperator() === NestedExpression::OR_OPERATOR) { |
606
|
1 |
|
return !$nestedExpression->isNegate(); |
607
|
|
|
} |
608
|
3 |
|
} |
609
|
|
|
|
610
|
|
|
|
611
|
3 |
|
if ($nestedExpression->getExpressionOperator() === NestedExpression::AND_OPERATOR) { |
612
|
1 |
|
return !$nestedExpression->isNegate(); |
613
|
2 |
|
} elseif ($nestedExpression->getExpressionOperator() === NestedExpression::OR_OPERATOR) { |
614
|
1 |
|
return $nestedExpression->isNegate(); |
615
|
|
|
} |
616
|
|
|
|
617
|
1 |
|
$errMsg = 'unknown field'; |
618
|
1 |
|
throw new InvalidArgumentException($errMsg); |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* Сравнение дат |
623
|
|
|
* |
624
|
|
|
* @param DateTime $value1 |
625
|
|
|
* @param DateTime $value2 |
626
|
|
|
* @param integer $operator |
627
|
|
|
* |
628
|
|
|
* @return bool |
629
|
|
|
* @throws InvalidArgumentException |
630
|
|
|
*/ |
631
|
2 |
|
private function compareDate(DateTime $value1, DateTime $value2, $operator) |
632
|
|
|
{ |
633
|
2 |
|
$diff = $value1->format('U') - $value2->format('U'); |
634
|
|
|
switch ($operator) { |
635
|
2 |
|
case FieldExpression::EQUALS: |
636
|
2 |
|
return $diff === 0; |
637
|
1 |
|
case FieldExpression::NOT_EQUALS: |
638
|
1 |
|
return $diff !== 0; |
639
|
|
|
|
640
|
1 |
|
case FieldExpression::GT: |
641
|
1 |
|
return $diff > 0; |
642
|
|
|
|
643
|
1 |
|
case FieldExpression::LT: |
644
|
1 |
|
return $diff < 0; |
645
|
|
|
} |
646
|
|
|
|
647
|
1 |
|
$errMsg = 'unknown field operator'; |
648
|
1 |
|
throw new InvalidArgumentException($errMsg); |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
/** |
652
|
|
|
* Сравнивает целые числа |
653
|
|
|
* |
654
|
|
|
* @param string $value1 |
655
|
|
|
* @param string $value2 |
656
|
|
|
* @param integer $operator |
657
|
|
|
* |
658
|
|
|
* @return bool |
659
|
|
|
* |
660
|
|
|
* @throws InvalidArgumentException |
661
|
|
|
*/ |
662
|
6 |
|
private function compareLong($value1, $value2, $operator) |
663
|
|
|
{ |
664
|
|
|
switch ($operator) { |
665
|
6 |
|
case FieldExpression::EQUALS: |
666
|
5 |
|
return $value1 === $value2; |
667
|
|
|
|
668
|
2 |
|
case FieldExpression::NOT_EQUALS: |
669
|
1 |
|
return $value1 !== $value2; |
670
|
|
|
|
671
|
2 |
|
case FieldExpression::GT: |
672
|
1 |
|
return $value1 > $value2; |
673
|
|
|
|
674
|
2 |
|
case FieldExpression::LT: |
675
|
1 |
|
return $value1 < $value2; |
676
|
|
|
} |
677
|
|
|
|
678
|
1 |
|
$errMsg = 'unknown field operator'; |
679
|
1 |
|
throw new InvalidArgumentException($errMsg); |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
/** |
683
|
|
|
* |
684
|
|
|
* @todo поправить для юникода |
685
|
|
|
* |
686
|
|
|
* Сравнение строк |
687
|
|
|
* |
688
|
|
|
* @param $value1 |
689
|
|
|
* @param $value2 |
690
|
|
|
* @param $operator |
691
|
|
|
* |
692
|
|
|
* @return bool |
693
|
|
|
* |
694
|
|
|
* @throws \OldTown\Workflow\Exception\InvalidArgumentException |
695
|
|
|
*/ |
696
|
5 |
|
private function compareText($value1, $value2, $operator) |
697
|
|
|
{ |
698
|
|
|
switch ($operator) { |
699
|
5 |
|
case FieldExpression::EQUALS: |
700
|
4 |
|
return $value1 === $value2; |
701
|
|
|
|
702
|
2 |
|
case FieldExpression::NOT_EQUALS: |
703
|
1 |
|
return $value1 !== $value2; |
704
|
|
|
|
705
|
2 |
|
case FieldExpression::GT: |
706
|
1 |
|
return strlen($value1) > strlen($value2); |
707
|
|
|
|
708
|
2 |
|
case FieldExpression::LT: |
709
|
1 |
|
return strlen($value1) < strlen($value2); |
710
|
|
|
} |
711
|
|
|
|
712
|
1 |
|
$errMsg = 'unknown field operator'; |
713
|
1 |
|
throw new InvalidArgumentException($errMsg); |
714
|
|
|
} |
715
|
|
|
} |
716
|
|
|
|
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.