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.

WorkflowEngineContext   B
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 351
Duplicated Lines 10.26 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 37
c 1
b 0
f 0
lcom 1
cbo 11
dl 36
loc 351
rs 8.6

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A init() 0 9 1
A beforeScenarioHandler() 0 9 1
A registerAWorkflowWithTheNameWithXml() 0 17 3
B createWorkflowDescriptor() 0 37 4
A createWorkflowManager() 0 23 2
A initializeWorkflowEntry() 18 18 3
A callActionWithIdForWorkflowProcessWithAlias() 18 18 3
A lastActionWasTheResultOfClassExceptionTheMassageOfException() 0 12 3
A getWorkflowManager() 0 9 2
A getEntryIdByAlias() 0 9 2
C validateCurrentSteps() 0 28 7
A exceptionsAreMissing() 0 6 2
A thereIsTheValuableWithValueInTransientVars() 0 13 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @link    https://github.com/old-town/old-town-workflow
4
 * @author  Malofeykin Andrey  <[email protected]>
5
 */
6
namespace OldTownWorkflowBehatTestBootstrap;
7
8
use Behat\Behat\Context\Context;
9
use Behat\Behat\Context\SnippetAcceptingContext;
10
use Behat\Gherkin\Node\PyStringNode;
11
use OldTown\Workflow\Loader\WorkflowDescriptor;
12
use OldTown\Workflow\Basic\BasicWorkflow;
13
use OldTown\Workflow\Config\ArrayConfiguration;
14
use OldTown\Workflow\Spi\Memory\MemoryWorkflowStore;
15
use OldTown\Workflow\Loader\CallbackWorkflowFactory;
16
use OldTown\Workflow\Util\Properties\Properties;
17
use Behat\Gherkin\Node\TableNode;
18
use OldTown\Workflow\TransientVars\TransientVarsInterface;
19
use OldTown\Workflow\TransientVars\BaseTransientVars;
20
use Exception;
21
use RuntimeException;
22
use DOMElement;
23
24
/**
25
 * Class WorkflowEngineContext
26
 */
27
class WorkflowEngineContext implements Context, SnippetAcceptingContext
28
{
29
    /**
30
     * @var array
31
     */
32
    protected $workflows = [];
33
34
    /**
35
     * @var null|callable
36
     */
37
    protected $callbackFactory;
38
39
    /**
40
     * @var BasicWorkflow
41
     */
42
    protected $workflowManager;
43
44
    /**
45
     * @var bool
46
     */
47
    protected $flagInitWorkflowManager = false;
48
49
    /**
50
     * Ключем является alias для идендфикатора запущенного процесса workflow. А значением id этого процесса
51
     *
52
     * @var array
53
     */
54
    protected $entryAliasToEntryId = [];
55
56
    /**
57
     * @var Exception|null
58
     */
59
    protected $lastException;
60
61
    /**
62
     * @var TransientVarsInterface
63
     */
64
    protected $transientVars;
65
66
    /**
67
     *
68
     */
69
    public function __construct()
70
    {
71
        $this->init();
72
    }
73
74
    /**
75
     * @return void
76
     */
77
    protected function init()
78
    {
79
        $this->callbackFactory = function (WorkflowDescriptor $descriptor) {
80
            return function () use ($descriptor) {
81
                return $descriptor;
82
            };
83
        };
84
        $this->transientVars = new BaseTransientVars();
85
    }
86
87
    /**
88
     * @BeforeScenario
89
     */
90
    public function beforeScenarioHandler()
91
    {
92
        $this->workflows = [];
93
        $this->workflowManager = null;
94
        $this->flagInitWorkflowManager = false;
95
        $this->entryAliasToEntryId = [];
96
        $this->lastException = null;
97
        $this->transientVars = new BaseTransientVars();
98
    }
99
100
    /**
101
     * @Given : Registrate the workflow with the name :workflowName. With xml:
102
     *
103
     * @param string             $workflowName
104
     * @param PyStringNode $xml
105
     *
106
     * @throws RuntimeException
107
     */
108
    public function registerAWorkflowWithTheNameWithXml($workflowName, PyStringNode $xml)
109
    {
110
        if (true === $this->flagInitWorkflowManager) {
111
            $errMsg = 'The action can only be performed to create a workflow manager';
112
            throw new \RuntimeException($errMsg);
113
        }
114
115
        $descriptor = $this->createWorkflowDescriptor($xml);
116
        if (array_key_exists($workflowName, $this->workflows)) {
117
            $errMsg = sprintf('Workflow %s already exists', $workflowName);
118
            throw new \RuntimeException($errMsg);
119
        }
120
121
        $this->workflows[$workflowName] = [
122
            'callback' => call_user_func($this->callbackFactory, $descriptor)
123
        ];
124
    }
125
126
    /**
127
     * @param PyStringNode $xml
128
     *
129
     * @return WorkflowDescriptor
130
     *
131
     * @throws RuntimeException
132
     */
133
    public function createWorkflowDescriptor(PyStringNode $xml)
134
    {
135
        $useXmlErrors = libxml_use_internal_errors();
136
        try {
137
            libxml_use_internal_errors(true);
138
            libxml_clear_errors();
139
140
            $xmlDoc = new \DOMDocument();
141
            $xmlDoc->loadXML($xml->getRaw());
142
143
            $libxmlGetLastError = libxml_get_last_error();
144
            if ($libxmlGetLastError instanceof \LibXMLError) {
145
                throw new \RuntimeException($libxmlGetLastError->message, $libxmlGetLastError->code);
146
            }
147
148
            $rootCollection = $xmlDoc->getElementsByTagName('workflow');
149
            if (1 !== $rootCollection->length) {
150
                $errMsg = 'Incorrect structure workflow';
151
                throw new \RuntimeException($errMsg);
152
            }
153
            /** @var DOMElement $root */
154
            $root = $rootCollection->item(0);
155
156
            $r = new \ReflectionClass(WorkflowDescriptor::class);
157
            /** @var WorkflowDescriptor $descriptor */
158
            $descriptor = $r->newInstanceArgs([
159
                $root
160
            ]);
161
162
            libxml_use_internal_errors($useXmlErrors);
163
        } catch (\Exception $e) {
164
            libxml_clear_errors();
165
            libxml_use_internal_errors($useXmlErrors);
166
            throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
167
        }
168
        return $descriptor;
169
    }
170
171
    /**
172
     * @Given Create workflow manager
173
     *
174
     * @throws RuntimeException
175
     */
176
    public function createWorkflowManager()
177
    {
178
        try {
179
            $workflowManager = new BasicWorkflow(false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
180
181
            $properties = new  Properties();
182
            $properties->setProperty(CallbackWorkflowFactory::WORKFLOWS_PROPERTY, $this->workflows);
0 ignored issues
show
Documentation introduced by
$this->workflows is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
183
            $factory = new CallbackWorkflowFactory($properties);
184
185
            $configuration = new ArrayConfiguration([
186
                ArrayConfiguration::PERSISTENCE => MemoryWorkflowStore::class,
187
                ArrayConfiguration::PERSISTENCE_ARGS => [],
188
                ArrayConfiguration::WORKFLOW_FACTORY => $factory
189
            ]);
190
191
            $workflowManager->setConfiguration($configuration);
192
193
            $this->workflowManager = $workflowManager;
194
            $this->flagInitWorkflowManager = true;
195
        } catch (\Exception $e) {
196
            throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
197
        }
198
    }
199
200
    /**
201
     * @When Progress workflow with alias :entryAlias. Workflow name: :workflowName. Initial action id: :initialAction
202
     *
203
     * @param string $entryAlias
204
     * @param string $workflowName
205
     * @param integer $initialAction
206
     *
207
     * @throws \RuntimeException
208
     */
209 View Code Duplication
    public function initializeWorkflowEntry($entryAlias, $workflowName, $initialAction)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
210
    {
211
        $entryAlias = (string)$entryAlias;
212
        if (array_key_exists($entryAlias, $this->entryAliasToEntryId)) {
213
            $errMsg = sprintf('Alias %s already exists', $entryAlias);
214
            throw new \RuntimeException($errMsg);
215
        }
216
217
        $workflowManager = $this->getWorkflowManager();
218
219
        try {
220
            $entryId = $workflowManager->initialize($workflowName, $initialAction, $this->transientVars);
221
            $this->entryAliasToEntryId[$entryAlias] = $entryId;
222
        } catch (\Exception $e) {
223
            $this->lastException = $e;
224
            //throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
225
        }
226
    }
227
228
    /**
229
     * @When Call action with id=:actionId for workflow process with alias :entryAlias
230
     *
231
     * @param $entryAlias
232
     * @param $actionId
233
     *
234
     * @throws \RuntimeException
235
     */
236 View Code Duplication
    public function callActionWithIdForWorkflowProcessWithAlias($entryAlias, $actionId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
237
    {
238
        $entryAlias = (string)$entryAlias;
239
        if (!array_key_exists($entryAlias, $this->entryAliasToEntryId)) {
240
            $errMsg = sprintf('Alias %s not exists', $entryAlias);
241
            throw new \RuntimeException($errMsg);
242
        }
243
        $entryId = $this->entryAliasToEntryId[$entryAlias];
244
245
        $workflowManager = $this->getWorkflowManager();
246
247
        try {
248
            $workflowManager->doAction($entryId, $actionId, $this->transientVars);
249
        } catch (\Exception $e) {
250
            $this->lastException = $e;
251
            //throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
252
        }
253
    }
254
255
    /**
256
     * @Then Last action was the result of class exception :exceptionClassName. The massage of exception: :exceptionText
257
     *
258
     * @param $exceptionClassName
259
     * @param $exceptionText
260
     *
261
     * @throws \RuntimeException
262
     */
263
    public function lastActionWasTheResultOfClassExceptionTheMassageOfException($exceptionClassName, $exceptionText)
264
    {
265
        if (!$this->lastException instanceof $exceptionClassName) {
266
            $errMsg = sprintf('Last action was the result of class exception "%s"', $exceptionClassName);
267
            throw new \RuntimeException($errMsg);
268
        }
269
270
        if ($exceptionText !== $this->lastException->getMessage()) {
271
            $errMsg = sprintf('Invalid text exception. Expected %s', $exceptionText);
272
            throw new \RuntimeException($errMsg);
273
        }
274
    }
275
276
    /**
277
     * @return BasicWorkflow
278
     *
279
     * @throws \RuntimeException
280
     */
281
    protected function getWorkflowManager()
282
    {
283
        if (null === $this->workflowManager) {
284
            $errMsg = 'The  WorkflowManager has not been established';
285
            throw new \RuntimeException($errMsg);
286
        }
287
288
        return $this->workflowManager;
289
    }
290
291
    /**
292
     * @param string $entryAlias
293
     * @return integer
294
     *
295
     * @throws \RuntimeException
296
     */
297
    protected function getEntryIdByAlias($entryAlias)
298
    {
299
        if (!array_key_exists($entryAlias, $this->entryAliasToEntryId)) {
300
            $errMsg = sprintf('The  WorkflowManager has not been established: Alias %s not exists', $entryAlias);
301
            throw new \RuntimeException($errMsg);
302
        }
303
304
        return $this->entryAliasToEntryId[$entryAlias];
305
    }
306
307
    /**
308
     * @Then Process of workflow with the alias :entryAlias has the below steps:
309
     *
310
     * @param string          $entryAlias
311
     * @param TableNode $steps
312
     *
313
     * @throws \RuntimeException
314
     */
315
    public function validateCurrentSteps($entryAlias, TableNode $steps)
316
    {
317
        $entryId = $this->getEntryIdByAlias($entryAlias);
318
319
        $currentSteps = $this->getWorkflowManager()->getConfiguration()->getWorkflowStore()->findCurrentSteps($entryId);
320
        $actualCurrentSteps = [];
321
        foreach ($currentSteps as $currentStep) {
322
            $actualCurrentSteps[(integer)$currentStep->getStepId()] = $currentStep;
323
        }
324
325
        $stepsColumn = $steps->getColumn(0);
326
        if (count($stepsColumn) < 2 || 'stepId' !== array_shift($stepsColumn)) {
327
            $errMsg = 'Incorrect step id list';
328
            throw new \RuntimeException($errMsg);
329
        }
330
331
        foreach ($stepsColumn as $currentStepFromColumn) {
332
            $currentStepFromColumn = (integer)$currentStepFromColumn;
333
            if (!array_key_exists($currentStepFromColumn, $actualCurrentSteps)) {
334
                $errMsg = sprintf('Step not found %s', $currentStepFromColumn);
335
                throw new \RuntimeException($errMsg);
336
            }
337
        }
338
339
        if (count($actualCurrentSteps) !== count($stepsColumn)) {
340
            throw new \RuntimeException('there are extra currentSteps ');
341
        }
342
    }
343
344
    /**
345
     * @Then Exceptions are missing
346
     *
347
     * @throws RuntimeException
348
     */
349
    public function exceptionsAreMissing()
350
    {
351
        if (null !== $this->lastException) {
352
            throw new \RuntimeException($this->lastException->getMessage(), $this->lastException->getCode(), $this->lastException);
353
        }
354
    }
355
356
    /**
357
     * @Then There is the valuable :name with value :value in Transient Vars
358
     *
359
     * @param string $name
360
     * @param string $value
361
     *
362
     * @throws \RuntimeException
363
     */
364
    public function thereIsTheValuableWithValueInTransientVars($name, $value)
365
    {
366
        if (!$this->transientVars->offsetExists($name)) {
367
            $errMsg = sprintf('Property %s not found in transient vars', $name);
368
            throw new \RuntimeException($errMsg);
369
        }
370
        $actual = $this->transientVars[$name];
371
372
        if ($value !== $actual) {
373
            $errMsg = sprintf('Property %s. Expected value %s. Actual %s', $name, $value, $actual);
374
            throw new \RuntimeException($errMsg);
375
        }
376
    }
377
}
378