Passed
Branch main (b0ee7b)
by Gaetano
09:00
created

WorkflowServiceInner   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 73
c 4
b 0
f 0
dl 0
loc 221
rs 9.52
wmc 36

12 Methods

Rating   Name   Duplication   Size   Complexity  
B parseMigrationDefinition() 0 30 9
A getReferenceValue() 0 14 5
A listReferences() 0 8 4
A executeMigration() 0 19 3
A executeMigrationInner() 0 12 2
A addMigration() 0 3 1
A restoreContext() 0 9 4
A getRegexp() 0 3 1
A migrationContextFromParameters() 0 20 2
A isReference() 0 7 2
A resolveReference() 0 6 2
A skipMigration() 0 3 1
1
<?php
2
3
namespace Kaliop\eZWorkflowEngineBundle\Core;
4
5
use Kaliop\eZMigrationBundle\API\Value\MigrationDefinition;
6
use Kaliop\eZMigrationBundle\API\Value\Migration;
7
use Kaliop\eZMigrationBundle\API\EnumerableReferenceResolverInterface;
8
use Kaliop\eZMigrationBundle\Core\MigrationService;
9
use Kaliop\eZMigrationBundle\Core\ReferenceResolver\PrefixBasedResolverInterface;
10
use Kaliop\eZWorkflowEngineBundle\API\Value\WorkflowDefinition;
11
12
class WorkflowServiceInner extends MigrationService implements PrefixBasedResolverInterface, EnumerableReferenceResolverInterface
13
{
14
    protected $eventPrefix = 'ez_workflow.';
15
    protected $eventEntity = 'workflow';
16
    protected $referenceRegexp = '/^workflow:/';
17
    protected $currentWorkflowName;
18
19
    public function addMigration(MigrationDefinition $migrationDefinition)
20
    {
21
        throw new \Exception("Unsupported operation: direct adding of workflows");
22
    }
23
24
    public function skipMigration(MigrationDefinition $migrationDefinition)
25
    {
26
        throw new \Exception("Unsupported operation: tagging of workflows as skipped");
27
    }
28
29
    /**
30
     * Reimplemented to make sure we always return a WorkflowDefinition
31
     * @param MigrationDefinition $migrationDefinition this should be a WorkflowDefinition really
32
     * @return WorkflowDefinition
33
     * @throws \Exception
34
     */
35
    public function parseMigrationDefinition(MigrationDefinition $migrationDefinition)
36
    {
37
        foreach ($this->DefinitionParsers as $definitionParser) {
38
            if ($definitionParser->supports($migrationDefinition->name)) {
39
                // parse the source file
40
                $migrationDefinition = $definitionParser->parseMigrationDefinition($migrationDefinition);
41
42
                // and make sure we know how to handle all steps
43
                foreach ($migrationDefinition->steps as $step) {
44
                    if (!isset($this->executors[$step->type])) {
45
                        return new WorkflowDefinition(
46
                            $migrationDefinition->name,
47
                            $migrationDefinition->path,
48
                            $migrationDefinition->rawDefinition,
49
                            MigrationDefinition::STATUS_INVALID,
50
                            array(),
51
                            "Can not handle workflow step of type '{$step->type}'",
52
                            isset($migrationDefinition->signalName) ? $migrationDefinition->signalName : null,
53
                            isset($migrationDefinition->runAs) ? $migrationDefinition->runAs : false,
54
                            isset($migrationDefinition->useTransaction) ? $migrationDefinition->useTransaction : false,
55
                            isset($migrationDefinition->avoidRecursion) ? $migrationDefinition->avoidRecursion : false
56
                        );
57
                    }
58
                }
59
60
                return $migrationDefinition;
61
            }
62
        }
63
64
        throw new \Exception("No parser available to parse workflow definition '{$migrationDefinition->name}'");
65
    }
66
67
    /**
68
     * Reimplemented to add more parameters to be stored in the context
69
     *
70
     * @param MigrationDefinition $migrationDefinition
71
     * @param bool $useTransaction when set to false, no repo transaction will be used to wrap the migration
72
     * @param string $defaultLanguageCode
73
     * @param string|int|false|null $adminLogin when false, current user is used; when null, hardcoded admin account
74
     * @param $workflowParameters
75
     * @throws \Exception
76
     *
77
     * @todo treating a null and false $adminLogin values differently is prone to hard-to-track errors.
78
     *       Shall we use instead -1 to indicate the desire to not-login-as-admin-user-at-all ?
79
     */
80
    public function executeMigration(MigrationDefinition $migrationDefinition, $useTransaction = true,
81
        $defaultLanguageCode = null, $adminLogin = null, $force = false, $forceSigchildEnabled = null, $workflowParameters = null)
82
    {
83
        if ($migrationDefinition->status == MigrationDefinition::STATUS_TO_PARSE) {
84
            $migrationDefinition = $this->parseMigrationDefinition($migrationDefinition);
85
        }
86
87
        if ($migrationDefinition->status == MigrationDefinition::STATUS_INVALID) {
88
            /// @todo !important name of entity should be gotten dynamically (migration vs. workflow)
89
            throw new \Exception("Can not execute migration '{$migrationDefinition->name}': {$migrationDefinition->parsingError}");
90
        }
91
92
        /// @todo add support for setting in $migrationContext a userContentType ?
93
        $migrationContext = $this->migrationContextFromParameters($defaultLanguageCode, $adminLogin, $forceSigchildEnabled, $workflowParameters);
0 ignored issues
show
Bug introduced by
It seems like $defaultLanguageCode can also be of type string; however, parameter $defaultLanguageCode of Kaliop\eZWorkflowEngineB...ContextFromParameters() does only seem to accept null, 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

93
        $migrationContext = $this->migrationContextFromParameters(/** @scrutinizer ignore-type */ $defaultLanguageCode, $adminLogin, $forceSigchildEnabled, $workflowParameters);
Loading history...
Bug introduced by
It seems like $adminLogin can also be of type false and integer and string; however, parameter $adminLogin of Kaliop\eZWorkflowEngineB...ContextFromParameters() does only seem to accept null, 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

93
        $migrationContext = $this->migrationContextFromParameters($defaultLanguageCode, /** @scrutinizer ignore-type */ $adminLogin, $forceSigchildEnabled, $workflowParameters);
Loading history...
94
95
        // set migration as begun - has to be in own db transaction
96
        $migration = $this->storageHandler->startMigration($migrationDefinition, $force);
97
98
        $this->executeMigrationInner($migration, $migrationDefinition, $migrationContext, 0, $useTransaction, $adminLogin);
99
    }
100
101
    /**
102
     * Reimplemented to store the name of the current executing workflow
103
     * @param Migration $migration
104
     * @param MigrationDefinition $migrationDefinition
105
     * @param array $migrationContext
106
     * @param int $stepOffset
107
     * @param bool $useTransaction when set to false, no repo transaction will be used to wrap the migration
108
     * @param string|int|false|null $adminLogin used only for committing db transaction if needed. If false or null, hardcoded admin is used
109
     * @throws \Exception
110
     */
111
    protected function executeMigrationInner(Migration $migration, MigrationDefinition $migrationDefinition,
112
        $migrationContext, $stepOffset = 0, $useTransaction = true, $adminLogin = null)
113
    {
114
        $previousWorkflowName = $this->currentWorkflowName;
115
        $this->currentWorkflowName = $migration->name;
116
        try {
117
            parent::executeMigrationInner($migration, $migrationDefinition, $migrationContext, $stepOffset,
118
                $useTransaction, $adminLogin);
119
            $this->currentWorkflowName = $previousWorkflowName;
120
        } catch (\Exception $e) {
121
            $this->currentWorkflowName = $previousWorkflowName;
122
            throw $e;
123
        }
124
    }
125
126
    /**
127
     * Reimplemented to store in the context the current user at start of workflow
128
     *
129
     * @param null $defaultLanguageCode
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $defaultLanguageCode is correct as it would always require null to be passed?
Loading history...
130
     * @param null $adminLogin
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $adminLogin is correct as it would always require null to be passed?
Loading history...
131
     * @param array $workflowParameters
132
     * @return array
133
     */
134
    protected function migrationContextFromParameters($defaultLanguageCode = null, $adminLogin = null, $forceSigchildEnabled = null, $workflowParameters = null)
135
    {
136
        $properties = parent::migrationContextFromParameters($defaultLanguageCode, $adminLogin, $forceSigchildEnabled);
137
138
        if (!is_array($workflowParameters)) {
139
            /// @todo log warning
140
            $workflowParameters = array();
141
        }
142
143
        $workflowParameters = array_merge(
144
            array(
145
                'original_user' => $this->repository->getCurrentUser()->login,
146
                'start_time' => time()
147
            ),
148
            $workflowParameters
149
        );
150
151
        $properties['workflow'] = $workflowParameters;
152
153
        return $properties;
154
    }
155
156
    /**
157
     * When restoring the context of the original workflow, we will be running as anon, whereas the original
158
     * workflow might have been started either as an admin or as then-current user. We need special handling for the
159
     * latter case
160
     *
161
     * @param string $migrationName
162
     * @param array $context
163
     */
164
    public function restoreContext($migrationName, array $context)
165
    {
166
        if (array_key_exists('adminUserLogin', $context['context']) && $context['context']['adminUserLogin'] === false) {
167
            if (isset($context['context']['workflow']['original_user'])) {
168
                $context['context']['adminUserLogin'] = $context['context']['workflow']['original_user'];
169
            }
170
        }
171
172
        parent::restoreContext($migrationName, $context);
173
    }
174
175
    ### reference resolver interface
176
177
    public function getRegexp()
178
    {
179
        return $this->referenceRegexp;
180
    }
181
182
    public function isReference($stringIdentifier)
183
    {
184
        if (!is_string($stringIdentifier)) {
185
            return false;
186
        }
187
188
        return (bool)preg_match($this->referenceRegexp, $stringIdentifier);
189
    }
190
191
    /**
192
     * @param string $stringIdentifier
193
     * @return mixed
194
     * @throws \Exception if the given Identifier is not a reference
195
     */
196
    public function getReferenceValue($stringIdentifier)
197
    {
198
        $context = $this->getCurrentContext($this->currentWorkflowName);
199
        if (!is_array($context) || !isset($context['context']['workflow']) || !is_array($context['context']['workflow'])) {
0 ignored issues
show
introduced by
The condition is_array($context) is always true.
Loading history...
200
            throw new \Exception('Can not resolve reference to a workflow parameter as workflow context is missing');
201
        }
202
203
        $identifier = preg_replace($this->referenceRegexp, '', $stringIdentifier);
204
205
        if (!array_key_exists($identifier, $context['context']['workflow'])) {
206
            throw new \Exception("No workflow reference set with identifier '$identifier'");
207
        }
208
209
        return $context['context']['workflow'][$identifier];
210
    }
211
212
    /**
213
     * @param string $stringIdentifier
214
     * @return mixed $stringIdentifier if not a reference, otherwise the reference vale
215
     * @throws \Exception if the given Identifier is not a reference
216
     */
217
    public function resolveReference($stringIdentifier)
218
    {
219
        if ($this->isReference($stringIdentifier)) {
220
            return $this->getReferenceValue($stringIdentifier);
221
        }
222
        return $stringIdentifier;
223
    }
224
225
    public function listReferences()
226
    {
227
        $context = $this->getCurrentContext($this->currentWorkflowName);
228
        if (!is_array($context) || !isset($context['context']['workflow']) || !is_array($context['context']['workflow'])) {
0 ignored issues
show
introduced by
The condition is_array($context) is always true.
Loading history...
229
            throw new \Exception('Can not resolve reference to a workflow parameter as workflow context is missing');
230
        }
231
232
        return $context['context']['workflow'];
233
    }
234
}
235