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.

Dispatcher::getWorkflowDispatchEventClassName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\ReaderInterface;
12
use ReflectionClass;
13
use OldTown\Workflow\ZF2\Dispatch\Metadata\Target\Dispatch\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
use Zend\Log\LoggerInterface;
23
24
25
/**
26
 * Class Dispatcher
27
 *
28
 * @package OldTown\Workflow\ZF2\Dispatch\Dispatcher
29
 */
30
class Dispatcher implements DispatcherInterface
31
{
32
    use EventManagerAwareTrait;
33
34
    /**
35
     * @var string
36
     */
37
    const WORKFLOW_DISPATCH_EVENT = 'workflowDispatchEvent';
38
39
    /**
40
     * Имя класса события
41
     *
42
     * @var string
43
     */
44
    protected $workflowDispatchEventClassName = WorkflowDispatchEvent::class;
45
46
    /**
47
     * Имя класса события
48
     *
49
     * @var string
50
     */
51
    protected $transientVarsClassName = BaseTransientVars::class;
52
53
    /**
54
     * @var WorkflowService
55
     */
56
    protected $workflowService;
57
58
    /**
59
     * @var ReaderInterface
60
     */
61
    protected $metadataReader;
62
63
    /**
64
     * @var ValidatorPluginManager
65
     */
66
    protected $validatorManager;
67
68
    /**
69
     * Логер
70
     *
71
     * @var LoggerInterface
72
     */
73
    protected $log;
74
75
    /**
76
     * @param array $options
77
     */
78
    public function __construct(array $options = [])
79
    {
80
        $initOptions = [
81
            array_key_exists('workflowService', $options) ? $options['workflowService'] : null,
82
            array_key_exists('metadataReader', $options) ? $options['metadataReader'] : null,
83
            array_key_exists('validatorManager', $options) ? $options['validatorManager'] : null,
84
            array_key_exists('log', $options) ? $options['log'] : null,
85
        ];
86
        call_user_func_array([$this, 'init'], $initOptions);
87
    }
88
89
    /**
90
     * @param WorkflowService        $workflowService
91
     * @param ReaderInterface        $metadataReader
92
     * @param ValidatorPluginManager $validatorManager
93
     * @param LoggerInterface        $log
94
     */
95
    protected function init(WorkflowService $workflowService, ReaderInterface $metadataReader, ValidatorPluginManager $validatorManager, LoggerInterface $log)
96
    {
97
        $this->setWorkflowService($workflowService);
98
        $this->setMetadataReader($metadataReader);
99
        $this->setValidatorManager($validatorManager);
100
        $this->setLog($log);
101
    }
102
103
    /**
104
     * Диспетчирезация работы с workflow
105
     *
106
     * @param WorkflowDispatchEventInterface $event
107
     *
108
     * @return void
109
     *
110
     * @throws Exception\RunWorkflowParamException
111
     */
112
    public function dispatch(WorkflowDispatchEventInterface $event)
113
    {
114
        $event->getMvcEvent()->setParam(static::WORKFLOW_DISPATCH_EVENT, $event);
115
        $event->setTarget($this);
116
117
118
        $this->getLog()->debug(
119
            sprintf(
120
                'Event: %s. Getting metadata to start scheduling cycle workflow',
121
                WorkflowDispatchEventInterface::LOAD_METADATA_EVENT
122
            )
123
        );
124
        $metadataResult = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::LOAD_METADATA_EVENT, $event, function ($test) {
125
            return ($test instanceof MetadataInterface);
126
        });
127
        $metadata = $metadataResult->last();
128
129
        if (!$metadata instanceof MetadataInterface) {
130
            $this->getLog()->info('No metadata to start scheduling workflow.');
131
            return;
132
        }
133
134
        $event->setMetadata($metadata);
135
136
        $prepareData = [];
137
        if ($metadata->isFlagRunPrepareData()) {
138
            $this->getLog()->info(
139
                sprintf(
140
                    'Event: %s. Preparing data to run Workflow',
141
                    WorkflowDispatchEventInterface::PREPARE_DATA_EVENT
142
                )
143
            );
144
            $prepareDataResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::PREPARE_DATA_EVENT, $event);
145
            foreach ($prepareDataResults as $prepareDataResult) {
146
                if (is_array($prepareDataResult) || $prepareDataResult instanceof Traversable) {
147
                    $prepareData = ArrayUtils::merge($prepareData, $prepareDataResult);
0 ignored issues
show
Bug introduced by
It seems like $prepareDataResult defined by $prepareDataResult on line 145 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...
148
                }
149
            }
150
        }
151
        $event->setPrepareData($prepareData);
152
153
154
        $flagRunWorkflow = $metadata->isWorkflowDispatch();
155
        if (true === $flagRunWorkflow) {
156
            $this->getLog()->info(
157
                sprintf(
158
                    'Event: %s. Checking the workflow start conditions',
159
                    WorkflowDispatchEventInterface::CHECK_RUN_WORKFLOW_EVENT
160
                )
161
            );
162
            $dispatchConditionsResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::CHECK_RUN_WORKFLOW_EVENT, $event);
163
            foreach ($dispatchConditionsResults as $dispatchConditionsResult) {
164
                if (false === $dispatchConditionsResult) {
165
                    $this->getLog()->info('Launch Workflow canceled.');
166
                    $flagRunWorkflow = false;
167
                    break;
168
                }
169
            }
170
        }
171
172
        if (true === $flagRunWorkflow) {
173
            $this->getLog()->info(
174
                sprintf(
175
                    'Event: %s. Getting metadata workflow to run',
176
                    WorkflowDispatchEventInterface::METADATA_WORKFLOW_TO_RUN_EVENT
177
                )
178
            );
179
            $runWorkflowParamResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::METADATA_WORKFLOW_TO_RUN_EVENT, $event, function ($result) {
180
                return ($result instanceof RunWorkflowParamInterface);
181
            });
182
            $runWorkflowParamResult = $runWorkflowParamResults->last();
183
184
            if (!$runWorkflowParamResult instanceof RunWorkflowParamInterface) {
185
                $errMsg = 'There is no evidence to launch workflow';
186
                throw new Exception\RunWorkflowParamException($errMsg);
187
            }
188
            $event->setRunWorkflowParam($runWorkflowParamResult);
189
190
            $this->getLog()->info(
191
                sprintf(
192
                    'Event: %s. Starting the workflow',
193
                    WorkflowDispatchEventInterface::RUN_WORKFLOW_EVENT
194
                )
195
            );
196
            $runWorkflowResults = $this->getEventManager()->trigger(WorkflowDispatchEventInterface::RUN_WORKFLOW_EVENT, $event, function ($result) {
197
                return ($result instanceof TransitionResultInterface);
198
            });
199
200
            $workflowResult = $runWorkflowResults->last();
201
            if ($workflowResult instanceof TransitionResultInterface) {
202
                $event->setWorkflowResult($workflowResult);
203
            }
204
        }
205
    }
206
207
    /**
208
     * Добавление подписчиков по умолчанию
209
     *
210
     */
211
    public function attachDefaultListeners()
212
    {
213
        $em = $this->getEventManager();
214
        $em->attach(WorkflowDispatchEventInterface::LOAD_METADATA_EVENT, [$this, 'onLoadMetadataHandler']);
215
        $em->attach(WorkflowDispatchEventInterface::PREPARE_DATA_EVENT, [$this, 'onPrepareDataHandler']);
216
        $em->attach(WorkflowDispatchEventInterface::CHECK_RUN_WORKFLOW_EVENT, [$this, 'onCheckRunWorkflowHandler']);
217
        $em->attach(WorkflowDispatchEventInterface::RUN_WORKFLOW_EVENT, [$this, 'onRunWorkflowHandler']);
218
    }
219
220
    /**
221
     * Получение метаданных
222
     *
223
     * @param WorkflowDispatchEventInterface $e
224
     *
225
     * @return MetadataInterface|null
226
     */
227
    public function onLoadMetadataHandler(WorkflowDispatchEventInterface $e)
228
    {
229
        $mvcEvent = $e->getMvcEvent();
230
        $controller = $mvcEvent->getTarget();
231
        if (!$controller instanceof AbstractController) {
232
            $this->getLog()->notice(
233
                'Unable to retrieve the metadata for scheduling workflow. No controller object in the property "target" MvcEvent.'
234
            );
235
            return null;
236
        }
237
238
        $routeMatch = $mvcEvent->getRouteMatch();
239
        if (!$routeMatch) {
240
            $this->getLog()->notice(
241
                'Unable to retrieve the metadata for scheduling workflow. Do not set RouteMatch'
242
            );
243
            return null;
244
        }
245
246
        $action = $routeMatch->getParam('action', 'not-found');
247
        $actionMethod = AbstractController::getMethodFromAction($action);
248
249
        if (!method_exists($controller, $actionMethod)) {
250
            $this->getLog()->notice(
251
                sprintf(
252
                    'Unable to retrieve the metadata for scheduling workflow. There is no action(%s) in controller(%s)',
253
                    $actionMethod,
254
                    get_class($controller)
255
                )
256
            );
257
            return null;
258
        }
259
260
        $controllerClassName = get_class($controller);
261
        $metadata = $this->getMetadataReader()->loadMetadataForAction($controllerClassName, $actionMethod);
262
263
        return $metadata;
264
    }
265
266
    /**
267
     * @param WorkflowDispatchEventInterface $e
268
     *
269
     * @return mixed|null
270
     *
271
     * @throws Exception\PrepareDataException
272
     */
273
    public function onPrepareDataHandler(WorkflowDispatchEventInterface $e)
274
    {
275
        $metadata = $e->getMetadata();
276
277
        $type = $metadata->getPrepareDataMethod();
278
        $handler = $metadata->getPrepareDataHandler();
279
280
        $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...
281
282
        if ('method' === $type) {
283
            $mvcEvent = $e->getMvcEvent();
284
            $controller = $mvcEvent->getTarget();
285
            if (!$controller instanceof AbstractController) {
286
                $errMsg = sprintf('Controller not implement %s', AbstractController::class);
287
                throw new Exception\PrepareDataException($errMsg);
288
            }
289
            $callback = [$controller, $handler];
290
            if (!is_callable($callback)) {
291
                $errMsg = sprintf('Invalid handler"%s"', $handler);
292
                throw new Exception\PrepareDataException($errMsg);
293
            }
294
            $prepareDataResult = call_user_func($callback, $e);
295
            if (null === $prepareDataResult) {
296
                $prepareDataResult = [];
297
            }
298
        } else {
299
            $errMsg = sprintf('Preparing data for Workflow will fail. Unknown handler type %s.', $type);
300
            throw new Exception\PrepareDataException($errMsg);
301
        }
302
303
        if (!is_array($prepareDataResult) && !$prepareDataResult instanceof Traversable) {
304
            $errMsg = 'Data preparation The results should be an array or Traversable';
305
            throw new Exception\PrepareDataException($errMsg);
306
        }
307
308
309
        return $prepareDataResult;
310
    }
311
312
    /**
313
     * Проверка, на то нужно ли запускать workflow
314
     *
315
     * @param WorkflowDispatchEventInterface $e
316
     *
317
     * @return boolean|null
318
     *
319
     * @throws \Zend\Validator\Exception\InvalidArgumentException
320
     * @throws  Exception\PrepareDataException
321
     */
322
    public function onCheckRunWorkflowHandler(WorkflowDispatchEventInterface $e)
323
    {
324
        $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...
325
        if (!$metadata->getFlagHasConditions()) {
326
            return null;
327
        }
328
329
        try {
330
            $conditions = $metadata->getConditions();
331
332
            $validatorManager = $this->getValidatorManager();
333
334
            /** @var ValidatorChain $validatorChains */
335
            $validatorChains = $validatorManager->get(ValidatorChain::class);
336
        } catch (\Exception $e) {
337
            throw new Exception\PrepareDataException($e->getMessage(), $e->getCode(), $e);
338
        }
339
340
341
342
        $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...
343
        $controller = $mvcEvent->getTarget();
344
        if (!$controller instanceof AbstractController) {
345
            $controller = null;
346
        }
347
348
349
        foreach ($conditions as $condition) {
350
            try {
351
                $type = $condition->getType();
352
                $handler = $condition->getHandler();
353
                switch ($type) {
354
                    case 'method': {
355
                        if (null === $controller) {
356
                            $errMsg = 'Controller not specified';
357
                            throw new Exception\CheckRunWorkflowEventException($errMsg);
358
                        }
359
                        $callback = [$controller, $handler];
360
361
                        /** @var ValidatorInterface $callbackValidator */
362
                        $callbackValidator = $validatorManager->get('callback', $callback);
363
364
                        $validatorChains->attach($callbackValidator);
365
366
                        break;
367
                    }
368
                    case 'service': {
369
                        $validatorParams = $condition->getParams();
370
                        /** @var ValidatorInterface $validator */
371
                        $validator = $validatorManager->get($handler, $validatorParams);
372
373
                        $validatorChains->attach($validator);
374
375
                        break;
376
                    }
377
                    default: {
378
                        $errMsg = sprintf('Preparing data for Workflow will fail. Unknown handler type %s.', $type);
379
                        throw new Exception\PrepareDataException($errMsg);
380
                    }
381
                }
382
            } catch (\Exception $e) {
383
                throw new Exception\PrepareDataException($e->getMessage(), $e->getCode(), $e);
384
            }
385
        }
386
387
        return $validatorChains->isValid($e);
388
    }
389
390
    /**
391
     * Запуск workflow
392
     *
393
     * @param WorkflowDispatchEventInterface $e
394
     *
395
     * @return TransitionResultInterface
396
     *
397
     *
398
     * @throws Exception\InvalidArgumentException
399
     * @throws  Exception\WorkflowDispatchEventException
400
     * @throws \OldTown\Workflow\ZF2\ServiceEngine\Exception\InvalidInitializeWorkflowEntryException
401
     * @throws \OldTown\Workflow\ZF2\ServiceEngine\Exception\DoActionException
402
     */
403
    public function onRunWorkflowHandler(WorkflowDispatchEventInterface $e)
404
    {
405
        $runWorkflowParam = $e->getRunWorkflowParam();
406
        $runWorkflowParam->valid();
407
408
        $transientVars = $this->factoryTransientVars();
409
410
        $prepareData = $e->getPrepareData();
411
        foreach ($prepareData as $key => $value) {
412
            $transientVars[$key] = $value;
413
        }
414
415
        $runWorkflowParam = $e->getRunWorkflowParam();
416
        $runWorkflowParam->valid();
417
418
        $workflowManagerName = $runWorkflowParam->getManagerName();
419
        $workflowActionName = $runWorkflowParam->getActionName();
420
421
        $workflowActivity = $runWorkflowParam->getRunType();
422
        $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...
423
        switch ($runWorkflowParam->getRunType()) {
424
            case RunWorkflowParamInterface::WORKFLOW_RUN_INITIALIZE: {
425
                $workflowName = $runWorkflowParam->getWorkflowName();
426
                $result = $this->getWorkflowService()->initialize($workflowManagerName, $workflowName, $workflowActionName, $transientVars);
427
                break;
428
            }
429
            case RunWorkflowParamInterface::WORKFLOW_RUN_TYPE_DO_ACTION: {
430
                $entryId = $runWorkflowParam->getEntryId();
431
432
                $result = $this->getWorkflowService()->doAction($workflowManagerName, $entryId, $workflowActionName, $transientVars);
433
                break;
434
            }
435
            default: {
436
                $errMsg = sprintf('Invalid activity %s', $workflowActivity);
437
                throw new Exception\InvalidArgumentException($errMsg);
438
            }
439
        }
440
441
        return $result;
442
    }
443
444
    /**
445
     *
446
     * @return TransientVarsInterface
447
     *
448
     * @throws Exception\WorkflowDispatchEventException
449
     */
450
    public function factoryTransientVars()
451
    {
452
        $className = $this->getTransientVarsClassName();
453
454
        return $this->factoryClassName($className, TransientVarsInterface::class);
455
    }
456
457
    /**
458
     * Фабрика для создания событий
459
     *
460
     * @return WorkflowDispatchEventInterface
461
     *
462
     * @throws Exception\WorkflowDispatchEventException
463
     */
464
    public function workflowDispatchEventFactory()
465
    {
466
        $className = $this->getWorkflowDispatchEventClassName();
467
468
        return $this->factoryClassName($className, WorkflowDispatchEventInterface::class);
469
    }
470
471
    /**
472
     * Создает экземпляр класса и проверяет то что созданный объект имплементирует заданный интерфейс
473
     *
474
     * @param $className
475
     * @param $interface
476
     *
477
     * @return mixed
478
     *
479
     * @throws  Exception\WorkflowDispatchEventException
480
     */
481
    protected function factoryClassName($className, $interface)
482
    {
483
        $r = new ReflectionClass($className);
484
485
        $instance = $r->newInstance();
486
487
        if (!$instance instanceof $interface) {
488
            $errMsg = sprintf('Class %s not implement %s', $className, $interface);
489
            throw new Exception\WorkflowDispatchEventException($errMsg);
490
        }
491
492
        return $instance;
493
    }
494
495
    /**
496
     * @return WorkflowService
497
     */
498
    public function getWorkflowService()
499
    {
500
        return $this->workflowService;
501
    }
502
503
    /**
504
     * @param WorkflowService $workflowService
505
     *
506
     * @return $this
507
     */
508
    public function setWorkflowService(WorkflowService $workflowService)
509
    {
510
        $this->workflowService = $workflowService;
511
512
        return $this;
513
    }
514
515
    /**
516
     * @return ReaderInterface
517
     */
518
    public function getMetadataReader()
519
    {
520
        return $this->metadataReader;
521
    }
522
523
    /**
524
     * @param ReaderInterface $metadataReader
525
     *
526
     * @return $this
527
     */
528
    public function setMetadataReader(ReaderInterface $metadataReader)
529
    {
530
        $this->metadataReader = $metadataReader;
531
532
        return $this;
533
    }
534
535
    /**
536
     * @return ValidatorPluginManager
537
     */
538
    public function getValidatorManager()
539
    {
540
        return $this->validatorManager;
541
    }
542
543
    /**
544
     * @param ValidatorPluginManager $validatorManager
545
     *
546
     * @return $this
547
     */
548
    public function setValidatorManager(ValidatorPluginManager $validatorManager)
549
    {
550
        $this->validatorManager = $validatorManager;
551
552
        return $this;
553
    }
554
555
    /**
556
     * @return string
557
     */
558
    public function getWorkflowDispatchEventClassName()
559
    {
560
        return $this->workflowDispatchEventClassName;
561
    }
562
563
    /**
564
     * @param string $workflowDispatchEventClassName
565
     *
566
     * @return $this
567
     */
568
    public function setWorkflowDispatchEventClassName($workflowDispatchEventClassName)
569
    {
570
        $this->workflowDispatchEventClassName = (string)$workflowDispatchEventClassName;
571
572
        return $this;
573
    }
574
575
    /**
576
     * @return string
577
     */
578
    public function getTransientVarsClassName()
579
    {
580
        return $this->transientVarsClassName;
581
    }
582
583
    /**
584
     * @param string $transientVarsClassName
585
     *
586
     * @return $this
587
     */
588
    public function setTransientVarsClassName($transientVarsClassName)
589
    {
590
        $this->transientVarsClassName = (string)$transientVarsClassName;
591
592
        return $this;
593
    }
594
595
596
    /**
597
     * Устанавливает логер
598
     *
599
     * @return LoggerInterface
600
     */
601
    public function getLog()
602
    {
603
        return $this->log;
604
    }
605
606
    /**
607
     * Возвращает логер
608
     *
609
     * @param LoggerInterface $log
610
     *
611
     * @return $this
612
     */
613
    public function setLog(LoggerInterface $log)
614
    {
615
        $this->log = $log;
616
617
        return $this;
618
    }
619
}
620