GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — dev ( d5e133...46b2b0 )
by Андрей
03:20
created

Dispatcher::onCheckRunWorkflowHandler()   C

Complexity

Conditions 9
Paths 30

Size

Total Lines 67
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 67
rs 6.3448
cc 9
eloc 38
nc 30
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Dispatcher;
7
8
use OldTown\Workflow\TransientVars\TransientVarsInterface;
9
use Zend\EventManager\EventManagerAwareTrait;
10
use OldTown\Workflow\ZF2\ServiceEngine\Workflow as WorkflowService;
11
use OldTown\Workflow\ZF2\Dispatch\Metadata\Reader\ReaderInterface;
12
use ReflectionClass;
13
use OldTown\Workflow\ZF2\Dispatch\Metadata\Storage\MetadataInterface;
14
use Zend\Mvc\Controller\AbstractController;
15
use Traversable;
16
use Zend\Stdlib\ArrayUtils;
17
use Zend\Validator\ValidatorPluginManager;
18
use Zend\Validator\ValidatorChain;
19
use Zend\Validator\ValidatorInterface;
20
use OldTown\Workflow\TransientVars\BaseTransientVars;
21
use OldTown\Workflow\ZF2\ServiceEngine\Workflow\TransitionResultInterface;
22
23
/**
24
 * Class Dispatcher
25
 *
26
 * @package OldTown\Workflow\ZF2\Dispatch\Dispatcher
27
 */
28
class Dispatcher implements DispatcherInterface
29
{
30
    use EventManagerAwareTrait;
31
32
    /**
33
     * @var string
34
     */
35
    const WORKFLOW_DISPATCH_EVENT = 'workflowDispatchEvent';
36
37
    /**
38
     * Имя класса события
39
     *
40
     * @var string
41
     */
42
    protected $workflowDispatchEventClassName = WorkflowDispatchEvent::class;
43
44
    /**
45
     * Имя класса события
46
     *
47
     * @var string
48
     */
49
    protected $transientVarsClassName = BaseTransientVars::class;
50
51
    /**
52
     * @var WorkflowService
53
     */
54
    protected $workflowService;
55
56
    /**
57
     * @var ReaderInterface
58
     */
59
    protected $metadataReader;
60
61
    /**
62
     * @var ValidatorPluginManager
63
     */
64
    protected $validatorManager;
65
66
    /**
67
     * @param array $options
68
     */
69
    public function __construct(array $options = [])
70
    {
71
        call_user_func_array([$this, 'init'], $options);
72
    }
73
74
    /**
75
     * @param WorkflowService        $workflowService
76
     * @param ReaderInterface        $metadataReader
77
     * @param ValidatorPluginManager $validatorManager
78
     */
79
    protected function init(WorkflowService $workflowService, ReaderInterface $metadataReader, ValidatorPluginManager $validatorManager)
80
    {
81
        $this->setWorkflowService($workflowService);
82
        $this->setMetadataReader($metadataReader);
83
        $this->setValidatorManager($validatorManager);
84
    }
85
86
    /**
87
     * Диспетчирезация работы с workflow
88
     *
89
     * @param WorkflowDispatchEventInterface $event
90
     *
91
     * @return void
92
     */
93
    public function dispatch(WorkflowDispatchEventInterface $event)
94
    {
95
        $event->getMvcEvent()->setParam(static::WORKFLOW_DISPATCH_EVENT, $event);
96
        $event->setTarget($this);
97
98
        $metadataResult = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::LOAD_METADATA_EVENT, $event, function ($test) {
99
            return ($test instanceof MetadataInterface);
100
        });
101
        $metadata = $metadataResult->last();
102
103
        if (!$metadata instanceof MetadataInterface) {
104
            return;
105
        }
106
107
        $event->setMetadata($metadata);
108
109
        $prepareData = [];
110
        if ($metadata->isFlagRunPrepareData()) {
111
            $prepareDataResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::PREPARE_DATA_EVENT, $event);
112
            foreach ($prepareDataResults as $prepareDataResult) {
113
                if (is_array($prepareDataResult) || $prepareDataResult instanceof Traversable) {
114
                    $prepareData = ArrayUtils::merge($prepareData, $prepareDataResult);
0 ignored issues
show
Bug introduced by
It seems like $prepareDataResult defined by $prepareDataResult on line 112 can also be of type object<Traversable>; however, Zend\Stdlib\ArrayUtils::merge() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
115
                }
116
            }
117
        }
118
        $event->setPrepareData($prepareData);
119
120
121
        $flagRunWorkflow = $metadata->isWorkflowDispatch();
122
        if (true === $flagRunWorkflow) {
123
            $dispatchConditionsResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::CHECK_RUN_WORKFLOW_EVENT, $event);
124
            foreach ($dispatchConditionsResults as $dispatchConditionsResult) {
125
                if (false === $dispatchConditionsResult) {
126
                    $flagRunWorkflow = false;
127
                    break;
128
                }
129
            }
130
        }
131
132
        if (true === $flagRunWorkflow) {
133
            $runWorkflowResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::RUN_WORKFLOW_EVENT, $event, function ($result) {
134
                return ($result instanceof TransitionResultInterface);
135
            });
136
137
            $workflowResult = $runWorkflowResults->last();
138
            if ($workflowResult instanceof TransitionResultInterface) {
139
                $event->setWorkflowResult($workflowResult);
140
            }
141
        }
142
    }
143
144
    /**
145
     * Добавление подписчиков по умолчанию
146
     *
147
     */
148
    public function attachDefaultListeners()
149
    {
150
        $em = $this->getEventManager();
151
        $em->attach(WorkflowDispatchEventInterface::LOAD_METADATA_EVENT, [$this, 'onLoadMetadataHandler']);
152
        $em->attach(WorkflowDispatchEventInterface::PREPARE_DATA_EVENT, [$this, 'onPrepareDataHandler']);
153
        $em->attach(WorkflowDispatchEventInterface::CHECK_RUN_WORKFLOW_EVENT, [$this, 'onCheckRunWorkflowHandler']);
154
        $em->attach(WorkflowDispatchEventInterface::RUN_WORKFLOW_EVENT, [$this, 'onRunWorkflowHandler']);
155
    }
156
157
    /**
158
     * Получение метаданных
159
     *
160
     * @param WorkflowDispatchEventInterface $e
161
     *
162
     * @return MetadataInterface|null
163
     */
164
    public function onLoadMetadataHandler(WorkflowDispatchEventInterface $e)
165
    {
166
        $mvcEvent = $e->getMvcEvent();
167
        $controller = $mvcEvent->getTarget();
168
        if (!$controller instanceof AbstractController) {
169
            return null;
170
        }
171
172
        $routeMatch = $mvcEvent->getRouteMatch();
173
        if (!$routeMatch) {
174
            return null;
175
        }
176
177
        $action = $routeMatch->getParam('action', 'not-found');
178
        $actionMethod = AbstractController::getMethodFromAction($action);
179
180
        if (!method_exists($controller, $actionMethod)) {
181
            return null;
182
        }
183
184
        $controllerClassName = get_class($controller);
185
        $metadata = $this->getMetadataReader()->loadMetadataForAction($controllerClassName, $actionMethod);
186
187
        return $metadata;
188
    }
189
190
    /**
191
     * @param WorkflowDispatchEventInterface $e
192
     *
193
     * @return mixed|null
194
     *
195
     * @throws Exception\PrepareDataException
196
     */
197
    public function onPrepareDataHandler(WorkflowDispatchEventInterface $e)
198
    {
199
        $metadata = $e->getMetadata();
200
201
        $type = $metadata->getPrepareDataMethod();
202
        $handler = $metadata->getPrepareDataHandler();
203
204
        $prepareDataResult = null;
0 ignored issues
show
Unused Code introduced by
$prepareDataResult is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
205
206
        if ('method' === $type) {
207
            $mvcEvent = $e->getMvcEvent();
208
            $controller = $mvcEvent->getTarget();
209
            if (!$controller instanceof AbstractController) {
210
                $errMsg = sprintf('Controller not implement %s', AbstractController::class);
211
                throw new Exception\PrepareDataException($errMsg);
212
            }
213
            $callback = [$controller, $handler];
214
            if (!is_callable($callback)) {
215
                $errMsg = sprintf('Invalid handler"%s"', $handler);
216
                throw new Exception\PrepareDataException($errMsg);
217
            }
218
            $prepareDataResult = call_user_func($callback, $e);
219
            if (null === $prepareDataResult) {
220
                $prepareDataResult = [];
221
            }
222
        } else {
223
            $errMsg = sprintf('Preparing data for Workflow will fail. Unknown handler type %s.', $type);
224
            throw new Exception\PrepareDataException($errMsg);
225
        }
226
227
        if (!is_array($prepareDataResult) && !$prepareDataResult instanceof Traversable) {
228
            $errMsg = 'Data preparation The results should be an array or Traversable';
229
            throw new Exception\PrepareDataException($errMsg);
230
        }
231
232
233
        return $prepareDataResult;
234
    }
235
236
    /**
237
     * Проверка, на то нужно ли запускать workflow
238
     *
239
     * @param WorkflowDispatchEventInterface $e
240
     *
241
     * @return boolean|null
242
     *
243
     * @throws \Zend\Validator\Exception\InvalidArgumentException
244
     * @throws  Exception\PrepareDataException
245
     */
246
    public function onCheckRunWorkflowHandler(WorkflowDispatchEventInterface $e)
247
    {
248
        $metadata = $e->getMetadata();
0 ignored issues
show
Bug introduced by
The method getMetadata does only exist in OldTown\Workflow\ZF2\Dis...wDispatchEventInterface, but not in Exception.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
249
        if (!$metadata->getFlagHasConditions()) {
250
            return null;
251
        }
252
253
        try {
254
            $conditions = $metadata->getConditions();
255
256
            $validatorManager = $this->getValidatorManager();
257
258
            /** @var ValidatorChain $validatorChains */
259
            $validatorChains = $validatorManager->get(ValidatorChain::class);
260
        } catch (\Exception $e) {
261
            throw new Exception\PrepareDataException($e->getMessage(), $e->getCode(), $e);
262
        }
263
264
265
266
        $mvcEvent = $e->getMvcEvent();
0 ignored issues
show
Bug introduced by
The method getMvcEvent does only exist in OldTown\Workflow\ZF2\Dis...wDispatchEventInterface, but not in Exception.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
267
        $controller = $mvcEvent->getTarget();
268
        if (!$controller instanceof AbstractController) {
269
            $controller = null;
270
        }
271
272
273
        foreach ($conditions as $condition) {
274
            try {
275
                $type = $condition->getType();
276
                $handler = $condition->getHandler();
277
                switch ($type) {
278
                    case 'method': {
279
                        if (null === $controller) {
280
                            $errMsg = 'Controller not specified';
281
                            throw new Exception\CheckRunWorkflowEventException($errMsg);
282
                        }
283
                        $callback = [$controller, $handler];
284
285
                        /** @var ValidatorInterface $callbackValidator */
286
                        $callbackValidator = $validatorManager->get('callback', $callback);
287
288
                        $validatorChains->attach($callbackValidator);
289
290
                        break;
291
                    }
292
                    case 'service': {
293
                        $validatorParams = $condition->getParams();
294
                        /** @var ValidatorInterface $validator */
295
                        $validator = $validatorManager->get($handler, $validatorParams);
296
297
                        $validatorChains->attach($validator);
298
299
                        break;
300
                    }
301
                    default: {
302
                        $errMsg = sprintf('Preparing data for Workflow will fail. Unknown handler type %s.', $type);
303
                        throw new Exception\PrepareDataException($errMsg);
304
                    }
305
                }
306
            } catch (\Exception $e) {
307
                throw new Exception\PrepareDataException($e->getMessage(), $e->getCode(), $e);
308
            }
309
        }
310
311
        return $validatorChains->isValid($e);
312
    }
313
314
    /**
315
     * Запуск workflow
316
     *
317
     * @param WorkflowDispatchEventInterface $e
318
     *
319
     * @return TransitionResultInterface
320
     *
321
     *
322
     * @throws Exception\InvalidArgumentException
323
     * @throws  Exception\WorkflowDispatchEventException
324
     */
325
    public function onRunWorkflowHandler(WorkflowDispatchEventInterface $e)
326
    {
327
        $mvcEvent = $e->getMvcEvent();
328
329
        $routeMatch = $mvcEvent->getRouteMatch();
330
        if (!$routeMatch) {
331
            return null;
332
        }
333
334
        $metadata = $e->getMetadata();
335
336
        $workflowManagerNameParam = $metadata->getWorkflowManagerNameRouterParam();
337
        $workflowManagerName = $routeMatch->getParam($workflowManagerNameParam, null);
338
        if (null === $workflowManagerName) {
339
            $errMsg = sprintf('Param "%s" not found', $workflowManagerNameParam);
340
            throw new Exception\InvalidArgumentException($errMsg);
341
        }
342
343
        $workflowActionNameParam = $metadata->getWorkflowActionNameRouterParam();
344
        $workflowActionName = $routeMatch->getParam($workflowActionNameParam, null);
345
        if (null === $workflowActionName) {
346
            $errMsg = sprintf('Param "%s" not found', $workflowActionNameParam);
347
            throw new Exception\InvalidArgumentException($errMsg);
348
        }
349
350
351
        $workflowActivity = $metadata->getWorkflowRunType();
352
        $transientVars = $this->factoryTransientVars();
353
354
        $prepareData = $e->getPrepareData();
355
        foreach ($prepareData as $key => $value) {
356
            $transientVars[$key] = $value;
357
        }
358
359
        $result = null;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
360
        switch ($workflowActivity) {
361 View Code Duplication
            case 'initialize': {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
362
                $workflowNameParam = $metadata->getWorkflowNameRouterParam();
363
                $workflowName = $routeMatch->getParam($workflowNameParam, null);
364
                if (null === $workflowName) {
365
                    $errMsg = sprintf('Param "%s" not found', $workflowNameParam);
366
                    throw new Exception\InvalidArgumentException($errMsg);
367
                }
368
369
                $result = $this->getWorkflowService()->initialize($workflowManagerName, $workflowName, $workflowActionName, $transientVars);
370
                break;
371
            }
372 View Code Duplication
            case 'doAction': {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
373
                $entryIdParam = $metadata->getEntryIdRouterParam();
374
                $entryId = $routeMatch->getParam($entryIdParam, null);
375
                if (null === $entryId) {
376
                    $errMsg = sprintf('Param "%s" not found', $entryIdParam);
377
                    throw new Exception\InvalidArgumentException($errMsg);
378
                }
379
380
                $result = $this->getWorkflowService()->doAction($workflowManagerName, $entryId, $workflowActionName, $transientVars);
381
                break;
382
            }
383
            default: {
384
                $errMsg = sprintf('Invalid activity %s', $workflowActivity);
385
                throw new Exception\InvalidArgumentException($errMsg);
386
            }
387
        }
388
389
        return $result;
390
    }
391
392
    /**
393
     *
394
     * @return TransientVarsInterface
395
     *
396
     * @throws Exception\WorkflowDispatchEventException
397
     */
398
    public function factoryTransientVars()
399
    {
400
        $className = $this->getTransientVarsClassName();
401
402
        return $this->factoryClassName($className, TransientVarsInterface::class);
403
    }
404
405
    /**
406
     * Фабрика для создания событий
407
     *
408
     * @return WorkflowDispatchEventInterface
409
     *
410
     * @throws Exception\WorkflowDispatchEventException
411
     */
412
    public function workflowDispatchEventFactory()
413
    {
414
        $className = $this->getWorkflowDispatchEventClassName();
415
416
        return $this->factoryClassName($className, WorkflowDispatchEventInterface::class);
417
    }
418
419
    /**
420
     * Создает экземпляр класса и проверяет то что созданный объект имплементирует заданный интерфейс
421
     *
422
     * @param $className
423
     * @param $interface
424
     *
425
     * @return mixed
426
     *
427
     * @throws  Exception\WorkflowDispatchEventException
428
     */
429
    protected function factoryClassName($className, $interface)
430
    {
431
        $r = new ReflectionClass($className);
432
433
        $instance = $r->newInstance();
434
435
        if (!$instance instanceof $interface) {
436
            $errMsg = sprintf('Class %s not implement %s', $className, $interface);
437
            throw new Exception\WorkflowDispatchEventException($errMsg);
438
        }
439
440
        return $instance;
441
    }
442
443
    /**
444
     * @return WorkflowService
445
     */
446
    public function getWorkflowService()
447
    {
448
        return $this->workflowService;
449
    }
450
451
    /**
452
     * @param WorkflowService $workflowService
453
     *
454
     * @return $this
455
     */
456
    public function setWorkflowService(WorkflowService $workflowService)
457
    {
458
        $this->workflowService = $workflowService;
459
460
        return $this;
461
    }
462
463
    /**
464
     * @return ReaderInterface
465
     */
466
    public function getMetadataReader()
467
    {
468
        return $this->metadataReader;
469
    }
470
471
    /**
472
     * @param ReaderInterface $metadataReader
473
     *
474
     * @return $this
475
     */
476
    public function setMetadataReader(ReaderInterface $metadataReader)
477
    {
478
        $this->metadataReader = $metadataReader;
479
480
        return $this;
481
    }
482
483
    /**
484
     * @return ValidatorPluginManager
485
     */
486
    public function getValidatorManager()
487
    {
488
        return $this->validatorManager;
489
    }
490
491
    /**
492
     * @param ValidatorPluginManager $validatorManager
493
     *
494
     * @return $this
495
     */
496
    public function setValidatorManager(ValidatorPluginManager $validatorManager)
497
    {
498
        $this->validatorManager = $validatorManager;
499
500
        return $this;
501
    }
502
503
    /**
504
     * @return string
505
     */
506
    public function getWorkflowDispatchEventClassName()
507
    {
508
        return $this->workflowDispatchEventClassName;
509
    }
510
511
    /**
512
     * @param string $workflowDispatchEventClassName
513
     *
514
     * @return $this
515
     */
516
    public function setWorkflowDispatchEventClassName($workflowDispatchEventClassName)
517
    {
518
        $this->workflowDispatchEventClassName = (string)$workflowDispatchEventClassName;
519
520
        return $this;
521
    }
522
523
    /**
524
     * @return string
525
     */
526
    public function getTransientVarsClassName()
527
    {
528
        return $this->transientVarsClassName;
529
    }
530
531
    /**
532
     * @param string $transientVarsClassName
533
     *
534
     * @return $this
535
     */
536
    public function setTransientVarsClassName($transientVarsClassName)
537
    {
538
        $this->transientVarsClassName = (string)$transientVarsClassName;
539
540
        return $this;
541
    }
542
}
543