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.

StepDescriptor   D
last analyzed

Complexity

Total Complexity 59

Size/Duplication

Total Lines 460
Duplicated Lines 12.83 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 59
c 1
b 0
f 0
lcom 1
cbo 15
dl 59
loc 460
ccs 228
cts 228
cp 1
rs 4.5454

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
C init() 30 81 13
A getCommonActions() 0 4 1
A getPostFunctions() 0 4 1
A getPreFunctions() 0 4 1
A getMetaAttributes() 0 4 1
A setMetaAttributes() 0 6 1
A getPermissions() 0 4 1
A getActions() 0 4 1
A getAction() 0 10 3
A removeActions() 0 7 1
B resultsInJoin() 0 26 6
A getFlagHasActions() 0 4 1
C validate() 0 48 9
D writeXml() 29 99 16

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like StepDescriptor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use StepDescriptor, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @link    https://github.com/old-town/old-town-workflow
4
 * @author  Malofeykin Andrey  <[email protected]>
5
 */
6
namespace OldTown\Workflow\Loader;
7
8
use DOMElement;
9
use OldTown\Workflow\Exception\ArgumentNotNumericException;
10
use OldTown\Workflow\Exception\InvalidDescriptorException;
11
use OldTown\Workflow\Exception\InvalidParsingWorkflowException;
12
use OldTown\Workflow\Exception\InvalidWorkflowDescriptorException;
13
use OldTown\Workflow\Exception\InvalidWriteWorkflowException;
14
use SplObjectStorage;
15
use DOMDocument;
16
17
/**
18
 * Class ConditionDescriptor
19
 *
20
 * @package OldTown\Workflow\Loader
21
 */
22
class StepDescriptor extends AbstractDescriptor
23
    implements
24
        Traits\NameInterface,
25
        ValidateDescriptorInterface,
26
        WriteXmlInterface
27
{
28
    use Traits\NameTrait, Traits\IdTrait;
29
30
    /**
31
     * @var ActionDescriptor[]|SplObjectStorage
32
     */
33
    protected $actions;
34
35
    /**
36
     * Список id дейсвтия являющихся общими для всего workflow
37
     *
38
     * @var array
39
     */
40
    protected $commonActions = [];
41
42
    /**
43
     * @var FunctionDescriptor[]|SplObjectStorage
44
     */
45
    protected $postFunctions;
46
47
    /**
48
     * @var FunctionDescriptor[]|SplObjectStorage
49
     */
50
    protected $preFunctions;
51
52
    /**
53
     * @var PermissionDescriptor[]|SplObjectStorage
54
     */
55
    protected $permissions;
56
57
    /**
58
     * @var array
59
     */
60
    protected $metaAttributes = [];
61
62
    /**
63
     * Определяет есть ли действия для данного шага workflow
64
     *
65
     * @var bool
66
     */
67
    protected $hasActions = false;
68
69
70
    /**
71
     * @param DOMElement $element
72
     * @param AbstractDescriptor $parent
73
     *
74
     * @throws InvalidParsingWorkflowException
75
     */
76 69
    public function __construct(DOMElement $element = null, AbstractDescriptor $parent = null)
77
    {
78 69
        $this->preFunctions = new SplObjectStorage();
79 69
        $this->postFunctions = new SplObjectStorage();
80 69
        $this->actions = new SplObjectStorage();
81 69
        $this->permissions = new SplObjectStorage();
82
83 69
        parent::__construct($element);
84
85 69
        if (null !== $parent) {
86 64
            $this->setParent($parent);
87 64
        }
88 69
        if (null !== $element) {
89 65
            $this->init($element);
90 64
        }
91 68
    }
92
93
    /**
94
     * @param DOMElement $step
95
     *
96
     * @return void
97
     * @throws InvalidParsingWorkflowException
98
     */
99 65
    protected function init(DOMElement $step)
100
    {
101 65
        $this->parseId($step);
102 65
        $this->parseName($step);
103
104
105 65
        $metaElements = XmlUtil::getChildElements($step, 'meta');
106 65
        $metaAttributes = [];
107 65 View Code Duplication
        foreach ($metaElements as $meta) {
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...
108 1
            $value = XmlUtil::getText($meta);
109 1
            $name = XmlUtil::getRequiredAttributeValue($meta, 'name');
110
111 1
            $metaAttributes[$name] = $value;
112 65
        }
113 65
        $this->setMetaAttributes($metaAttributes);
114
115
        // set up pre-functions -- OPTIONAL
116 65
        $pre = XMLUtil::getChildElement($step, 'pre-functions');
117 65 View Code Duplication
        if (null !== $pre) {
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...
118 1
            $preFunctions = XMLUtil::getChildElements($pre, 'function');
119 1
            foreach ($preFunctions as $preFunction) {
120 1
                $functionDescriptor = DescriptorFactory::getFactory()->createFunctionDescriptor($preFunction);
121 1
                $functionDescriptor->setParent($this);
122 1
                $this->preFunctions->attach($functionDescriptor);
123 1
            }
124 1
        }
125
126
        // set up permissions - OPTIONAL
127 65
        $p = XMLUtil::getChildElement($step, 'external-permissions');
128 65 View Code Duplication
        if (null !== $p) {
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...
129 12
            $permissions = XMLUtil::getChildElements($p, 'permission');
130 12
            foreach ($permissions as $permission) {
131 12
                $permissionDescriptor = DescriptorFactory::getFactory()->createPermissionDescriptor($permission);
132 12
                $permissionDescriptor->setParent($this);
133 12
                $this->permissions->attach($permissionDescriptor);
134 12
            }
135 12
        }
136
137
        // set up actions - OPTIONAL
138 65
        $a = XMLUtil::getChildElement($step, 'actions');
139 65
        if (null !== $a) {
140 65
            $this->hasActions = true;
141
142 65
            $actions = XMLUtil::getChildElements($a, 'action');
143 65
            foreach ($actions as $action) {
144 55
                $actionDescriptor = DescriptorFactory::getFactory()->createActionDescriptor($action);
145 55
                $actionDescriptor->setParent($this);
146 55
                $this->actions->attach($actionDescriptor);
147 65
            }
148
149 65
            $commonActions = XMLUtil::getChildElements($a, 'common-action');
150
            /** @var WorkflowDescriptor $workflowDescriptor */
151 65
            $workflowDescriptor = $this->getParent();
152 65
            if (!$workflowDescriptor instanceof WorkflowDescriptor) {
153 1
                $errMsg = 'Отсутствует Workflow Descriptor';
154 1
                throw new InvalidParsingWorkflowException($errMsg);
155
            }
156 64
            foreach ($commonActions as $commonAction) {
157 12
                $actionId = XmlUtil::getRequiredAttributeValue($commonAction, 'id');
158 12
                $commonActionReference = $workflowDescriptor->getCommonAction($actionId);
159
160 12
                if ($commonActionReference !== null) {
161 6
                    $this->actions->attach($commonActionReference);
162 6
                }
163 12
                $this->commonActions[$actionId] = $actionId;
164 64
            }
165 64
        }
166
167
        // set up post-functions - OPTIONAL
168
169
        // set up post-functions - OPTIONAL
170 64
        $post = XMLUtil::getChildElement($step, 'post-functions');
171 64 View Code Duplication
        if (null !== $post) {
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...
172 2
            $postFunctions = XMLUtil::getChildElements($post, 'function');
173 2
            foreach ($postFunctions as $postFunction) {
174 2
                $functionDescriptor = DescriptorFactory::getFactory()->createFunctionDescriptor($postFunction);
175 2
                $functionDescriptor->setParent($this);
176 2
                $this->postFunctions->attach($functionDescriptor);
177 2
            }
178 2
        }
179 64
    }
180
181
    /**
182
     * Возвращает список id дейсвтий являющихся общим для всего workflow
183
     *
184
     * @return array
185
     */
186 22
    public function getCommonActions()
187
    {
188 22
        return $this->commonActions;
189
    }
190
191
192
    /**
193
     * @return FunctionDescriptor[]|SplObjectStorage
194
     */
195 26
    public function getPostFunctions()
196
    {
197 26
        return $this->postFunctions;
198
    }
199
200
    /**
201
     * @return FunctionDescriptor[]|SplObjectStorage
202
     */
203 36
    public function getPreFunctions()
204
    {
205 36
        return $this->preFunctions;
206
    }
207
208
    /**
209
     * @return array
210
     */
211 14
    public function getMetaAttributes()
212
    {
213 14
        return $this->metaAttributes;
214
    }
215
216
    /**
217
     * @param array $metaAttributes
218
     *
219
     * @return $this
220
     */
221 65
    public function setMetaAttributes(array $metaAttributes = [])
222
    {
223 65
        $this->metaAttributes = $metaAttributes;
224
225 65
        return $this;
226
    }
227
228
    /**
229
     * @return PermissionDescriptor[]|SplObjectStorage
230
     */
231 20
    public function getPermissions()
232
    {
233 20
        return $this->permissions;
234
    }
235
236
    /**
237
     * @return ActionDescriptor[]|SplObjectStorage
238
     */
239 47
    public function getActions()
240
    {
241 47
        return $this->actions;
242
    }
243
244
    /**
245
     * @param integer $id
246
     *
247
     * @return ActionDescriptor|null
248
     */
249 6
    public function getAction($id)
250
    {
251 6
        $id = (integer)$id;
252 6
        foreach ($this->actions as $action) {
253 5
            if ($id === $action->getId()) {
254 4
                return $action;
255
            }
256 2
        }
257 2
        return null;
258
    }
259
260
    /**
261
     * Удаляет действия для данного шага
262
     *
263
     * @return $this
264
     */
265 1
    public function removeActions()
266
    {
267 1
        $this->commonActions = [];
268 1
        $this->actions = new SplObjectStorage();
269 1
        $this->hasActions = false;
270 1
        return $this;
271
    }
272
273
    /**
274
     * @param integer $join
275
     * @return boolean
276
     *
277
     * @throws ArgumentNotNumericException
278
     */
279 4
    public function resultsInJoin($join)
280
    {
281 4
        if (!is_numeric($join)) {
282 1
            $errMsg = 'Аргумент должен быть числом';
283 1
            throw new ArgumentNotNumericException($errMsg);
284
        }
285
286 3
        $join = (integer)$join;
287
288 3
        $actions = $this->getActions();
289
290 3
        foreach ($actions as $actionDescriptor) {
291 3
            if ($join === $actionDescriptor->getUnconditionalResult()->getJoin()) {
292 1
                return true;
293
            }
294
295 2
            $results = $actionDescriptor->getConditionalResults();
296 2
            foreach ($results as $resultDescriptor) {
297 2
                if ($join === $resultDescriptor->getJoin()) {
298 1
                    return true;
299
                }
300 1
            }
301 1
        }
302
303 1
        return false;
304
    }
305
306
    /**
307
     * Возвращает флаг определяющий есть ли действия у данного шага
308
     *
309
     * @return boolean
310
     */
311 1
    public function getFlagHasActions()
312
    {
313 1
        return $this->hasActions;
314
    }
315
316
317
    /**
318
     * Валидация дескриптора
319
     *
320
     * @return void
321
     * @throws InvalidWorkflowDescriptorException
322
     */
323 20
    public function validate()
324
    {
325 20
        $commonActions = $this->getCommonActions();
326 20
        $actions = $this->getActions();
327 20
        $hasActions = $this->hasActions;
328
329 20
        if ($hasActions && 0 === count($commonActions) && 0 === $actions->count()) {
330 1
            $stepName = (string)$this->getName();
331 1
            $errMsg = sprintf('Шаг %s должен содержать одни действие или одно общее действие', $stepName);
332 1
            throw new InvalidWorkflowDescriptorException($errMsg);
333
        }
334
335 19
        if (-1 === $this->getId()) {
336 1
            $errMsg = 'В качестве id шага нельзя использовать -1, так как это зарезериврованное значение';
337 1
            throw new InvalidWorkflowDescriptorException($errMsg);
338
        }
339
340 18
        $preFunctions = $this->getPreFunctions();
341 18
        $postFunctions = $this->getPostFunctions();
342 18
        $actions = $this->getActions();
343 18
        $permissions = $this->getPermissions();
344
345 18
        ValidationHelper::validate($preFunctions);
346 18
        ValidationHelper::validate($postFunctions);
347 18
        ValidationHelper::validate($actions);
348 18
        ValidationHelper::validate($permissions);
349
350 18
        $workflowDescriptor = $this->getParent();
351 18
        if (!$workflowDescriptor instanceof WorkflowDescriptor) {
352 1
            $errMsg = sprintf('Родительский элемент для шага должен реализовывать %s', WorkflowDescriptor::class);
353 1
            throw new InvalidWorkflowDescriptorException($errMsg);
354
        }
355 17
        foreach ($commonActions as $actionId) {
356
            try {
357 4
                $commonActionReference = $workflowDescriptor->getCommonAction($actionId);
358
359 4
                if (null === $commonActionReference) {
360 1
                    $stepName = (string)$this->getName();
361 1
                    $errMsg = sprintf('Common-action %s указанное для шага %s не существует', $actionId, $stepName);
362 1
                    throw new InvalidWorkflowDescriptorException($errMsg);
363
                }
364 4
            } catch (\Exception $e) {
365 1
                $actionIdStr = (string)$actionId;
366 1
                $errMsg = sprintf('Некорректный id для common-action: id %s', $actionIdStr);
367 1
                throw  new InvalidWorkflowDescriptorException($errMsg, $e->getCode(), $e);
368
            }
369 17
        }
370 16
    }
371
372
373
    /**
374
     * Создает DOMElement - эквивалентный состоянию дескриптора
375
     *
376
     * @param DOMDocument $dom
377
     *
378
     * @return DOMElement|null
379
     * @throws InvalidDescriptorException
380
     * @throws InvalidWriteWorkflowException
381
     */
382 16
    public function writeXml(DOMDocument $dom = null)
383
    {
384 16
        if (null === $dom) {
385 1
            $errMsg = 'Не передан DOMDocument';
386 1
            throw new InvalidWriteWorkflowException($errMsg);
387
        }
388 15
        $descriptor = $dom->createElement('step');
389
390 15
        if (!$this->hasId()) {
391 1
            $errMsg = 'Отсутствует атрибут id';
392 1
            throw new InvalidDescriptorException($errMsg);
393
        }
394 14
        $id = $this->getId();
395 14
        $descriptor->setAttribute('id', $id);
396
397 14
        $name = (string)$this->getName();
398 14
        $name = trim($name);
399 14
        if (strlen($name) > 0) {
400 14
            $nameEncode = XmlUtil::encode($name);
401 14
            $descriptor->setAttribute('name', $nameEncode);
402 14
        }
403
404
405 14
        $metaAttributes = $this->getMetaAttributes();
406 14
        $baseMeta = $dom->createElement('meta');
407 14 View Code Duplication
        foreach ($metaAttributes as $metaAttributeName => $metaAttributeValue) {
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...
408 1
            $metaAttributeNameEncode = XmlUtil::encode($metaAttributeName);
409 1
            $metaAttributeValueEnEncode = XmlUtil::encode($metaAttributeValue);
410
411 1
            $metaElement = clone $baseMeta;
412 1
            $metaElement->setAttribute('name', $metaAttributeNameEncode);
413 1
            $metaValueElement = $dom->createTextNode($metaAttributeValueEnEncode);
414 1
            $metaElement->appendChild($metaValueElement);
415
416 1
            $descriptor->appendChild($metaElement);
417 14
        }
418
419
420 14
        $preFunctions = $this->getPreFunctions();
421 14 View Code Duplication
        if ($preFunctions->count() > 0) {
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...
422 1
            $preFunctionsElement = $dom->createElement('pre-functions');
423 1
            foreach ($preFunctions as $function) {
424 1
                $functionElement = $function->writeXml($dom);
425 1
                $preFunctionsElement->appendChild($functionElement);
426 1
            }
427
428 1
            $descriptor->appendChild($preFunctionsElement);
429 1
        }
430
431
432 14
        $permissions = $this->getPermissions();
433 14
        if ($permissions->count() > 0) {
434 12
            $permissionsElement = $dom->createElement('external-permissions');
435 12
            foreach ($permissions as $permission) {
436 12
                $permissionElement = $permission->writeXml($dom);
437 12
                $permissionsElement->appendChild($permissionElement);
438 12
            }
439
440 12
            $descriptor->appendChild($permissionsElement);
441 12
        }
442
443 14
        $actions = $this->getActions();
444 14
        $commonActions = $this->getCommonActions();
445
446 14
        if ($actions->count() > 0 || count($commonActions) > 0) {
447 14
            $actionsElement = $dom->createElement('actions');
448
449 14
            $commonActionElementBase = $dom->createElement('common-action');
450 14
            foreach ($commonActions as $commonActionId) {
451 3
                $commonActionElement = clone $commonActionElementBase;
452 3
                $commonActionElement->setAttribute('id', $commonActionId);
453
454 3
                $actionsElement->appendChild($commonActionElement);
455 14
            }
456
457 14
            foreach ($actions as $action) {
458 14
                if (!$action->isCommon()) {
459 13
                    $actionElement = $action->writeXml($dom);
460 13
                    $actionsElement->appendChild($actionElement);
461 13
                }
462 14
            }
463
464 14
            $descriptor->appendChild($actionsElement);
465 14
        }
466
467 14
        $postFunctions = $this->getPostFunctions();
468 14 View Code Duplication
        if ($postFunctions->count() > 0) {
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...
469 1
            $postFunctionsElement = $dom->createElement('post-functions');
470 1
            foreach ($postFunctions as $function) {
471 1
                $functionElement = $function->writeXml($dom);
472 1
                $postFunctionsElement->appendChild($functionElement);
473 1
            }
474
475 1
            $descriptor->appendChild($postFunctionsElement);
476 1
        }
477
478
479 14
        return $descriptor;
480
    }
481
}
482