Issues (2551)

src/Impl/ActivityExecutionTreeMapping.php (2 issues)

1
<?php
2
3
namespace Jabe\Impl;
4
5
use Jabe\ProcessEngineException;
6
use Jabe\Impl\Interceptor\CommandContext;
7
use Jabe\Impl\Persistence\Entity\ExecutionEntity;
8
use Jabe\Impl\Pvm\Process\{
9
    ProcessDefinitionImpl,
10
    ScopeImpl
11
};
12
use Jabe\Impl\Pvm\Runtime\{
13
    CompensationBehavior,
14
    PvmExecutionImpl
15
};
16
use Jabe\Impl\Util\EnsureUtil;
17
18
class ActivityExecutionTreeMapping
19
{
20
    protected $activityExecutionMapping = [];
21
    protected $commandContext;
22
    protected $processInstanceId;
23
    protected $processDefinition;
24
25
    public function __construct(CommandContext $commandContext, string $processInstanceId)
26
    {
27
        $this->commandContext = $commandContext;
28
        $this->processInstanceId = $processInstanceId;
29
        $this->initialize();
30
    }
31
32
    protected function submitExecution(ExecutionEntity $execution, ScopeImpl $scope): void
33
    {
34
        $this->addExecution($execution, $scope);
35
    }
36
37
    public function addExecution(ExecutionEntity $execution, ScopeImpl $scope): void
38
    {
39
        foreach ($this->activityExecutionMapping as $key => $pair) {
40
            if ($pair[0] == $scope) {
41
                $this->activityExecutionMapping[$key][] = $execution;
42
                return;
43
            }
44
        }
45
        $this->activityExecutionMapping[] = [$scope, $execution];
46
    }
47
48
    public function getExecutions(ScopeImpl $activity): array
49
    {
50
        foreach ($this->activityExecutionMapping as $key => $pair) {
51
            if ($pair[0] == $activity) {
52
                return array_slice($pair, 1);
53
            }
54
        }
55
        $this->activityExecutionMapping[] = [$activity];
56
        return [];
57
    }
58
59
    public function getExecution(ActivityInstance $activityInstance): ExecutionEntity
60
    {
61
        $scope = null;
62
63
        if ($activityInstance->getId() == $activityInstance->getProcessInstanceId()) {
64
            $scope = $this->processDefinition;
65
        } else {
66
            $scope = $this->processDefinition->findActivity($activityInstance->getActivityId());
67
        }
68
69
        return $this->intersect(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->intersect(...nce->getExecutionIds()) could return the type null which is incompatible with the type-hinted return Jabe\Impl\Persistence\Entity\ExecutionEntity. Consider adding an additional type-check to rule them out.
Loading history...
70
            $this->getExecutions($scope),
71
            $activityInstance->getExecutionIds()
72
        );
73
    }
74
75
    protected function intersect(array $executions, array $executionIds): ?ExecutionEntity
76
    {
77
        $executionIdSet = [];
78
        foreach ($executionIds as $executionId) {
79
            $executionIdSet[] = $executionId;
80
        }
81
82
        foreach ($executions as $execution) {
83
            if (in_array($execution->getId(), $executionIdSet)) {
84
                return $execution;
85
            }
86
        }
87
        throw new ProcessEngineException("Could not determine execution");
88
    }
89
90
    protected function initialize(): void
91
    {
92
        $processInstance = $this->commandContext->getExecutionManager()->findExecutionById($this->processInstanceId);
93
        $this->processDefinition = $processInstance->getProcessDefinition();
94
95
        $executions = $this->fetchExecutionsForProcessInstance($processInstance);
0 ignored issues
show
It seems like $processInstance can also be of type null; however, parameter $execution of Jabe\Impl\ActivityExecut...onsForProcessInstance() does only seem to accept Jabe\Impl\Persistence\Entity\ExecutionEntity, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
        $executions = $this->fetchExecutionsForProcessInstance(/** @scrutinizer ignore-type */ $processInstance);
Loading history...
96
        $executions[] = $processInstance;
97
98
        $leaves = $this->findLeaves($executions);
99
100
        $this->assignExecutionsToActivities($leaves);
101
    }
102
103
    protected function assignExecutionsToActivities(array $leaves): void
104
    {
105
        foreach ($leaves as $leaf) {
106
            $activity = $leaf->getActivity();
107
            if ($activity !== null) {
108
                if ($leaf->getActivityInstanceId() !== null) {
109
                    EnsureUtil::ensureNotNull("activity", "activity", $activity);
110
                    $this->submitExecution($leaf, $activity);
111
                }
112
                $this->mergeScopeExecutions($leaf);
113
            } elseif ($leaf->isProcessInstanceExecution()) {
114
                $this->submitExecution($leaf, $leaf->getProcessDefinition());
115
            }
116
        }
117
    }
118
119
    protected function mergeScopeExecutions(ExecutionEntity $leaf): void
120
    {
121
        $mapping = $leaf->createActivityExecutionMapping();
122
123
        foreach ($mapping as $pair) {
124
            $scope = $pair[0];
125
            $scopeExecution = $pair[1];
126
127
            $this->submitExecution($scopeExecution, $scope);
128
        }
129
    }
130
131
    protected function fetchExecutionsForProcessInstance(ExecutionEntity $execution): array
132
    {
133
        $executions = $execution->getExecutions();
134
        foreach ($execution->getExecutions() as $child) {
135
            $executions = array_merge($executions, $this->fetchExecutionsForProcessInstance($child));
136
        }
137
        return $executions;
138
    }
139
140
    protected function findLeaves(array $executions): array
141
    {
142
        $leaves = [];
143
144
        foreach ($executions as $execution) {
145
            if ($this->isLeaf($execution)) {
146
                $leaves[] = $execution;
147
            }
148
        }
149
150
        return $leaves;
151
    }
152
153
    /**
154
     * event-scope executions are not considered in this mapping and must be ignored
155
     */
156
    protected function isLeaf(ExecutionEntity $execution): bool
157
    {
158
        if (CompensationBehavior::isCompensationThrowing($execution)) {
159
            return true;
160
        } else {
161
            return !$execution->isEventScope() && empty($execution->getNonEventScopeExecutions());
162
        }
163
    }
164
}
165