Passed
Push — main ( 700fea...19aca0 )
by Gaetano
08:39
created

LoopExecutor::execute()   C

Complexity

Conditions 12
Paths 13

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 18.174

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 12
eloc 22
nc 13
nop 1
dl 0
loc 38
ccs 13
cts 20
cp 0.65
crap 18.174
rs 6.9666
c 2
b 0
f 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Kaliop\eZMigrationBundle\API\Exception\LoopBreakException;
6
use Kaliop\eZMigrationBundle\API\Exception\LoopContinueException;
7
use Kaliop\eZMigrationBundle\API\Exception\InvalidStepDefinitionException;
8
use Kaliop\eZMigrationBundle\API\Exception\MigrationStepSkippedException;
9
use Kaliop\eZMigrationBundle\API\ReferenceResolverInterface;
10
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
11
use Kaliop\eZMigrationBundle\Core\MigrationService;
12
use Kaliop\eZMigrationBundle\Core\ReferenceResolver\LoopResolver;
13
14
class LoopExecutor extends AbstractExecutor
15
{
16
    use IgnorableStepExecutorTrait;
0 ignored issues
show
Bug introduced by
The trait Kaliop\eZMigrationBundle...orableStepExecutorTrait requires the property $dsl which is not provided by Kaliop\eZMigrationBundle...e\Executor\LoopExecutor.
Loading history...
17
18
    protected $supportedStepTypes = array('loop');
19
    protected $supportedActions = array('repeat', 'iterate', 'break', 'continue');
20
21
    /** @var MigrationService $migrationService */
22
    protected $migrationService;
23
24
    /** @var LoopResolver $loopResolver */
25
    protected $loopResolver;
26
27
    public function __construct($migrationService, $loopResolver, ReferenceResolverInterface $referenceResolver)
28
    {
29 149
        $this->migrationService = $migrationService;
30
        $this->loopResolver = $loopResolver;
31 149
        $this->referenceResolver = $referenceResolver;
32 149
    }
33 149
34 149
    /**
35
     * @param MigrationStep $step
36
     * @return mixed
37
     * @throws InvalidStepDefinitionException
38
     * @throws \Exception
39
     */
40
    public function execute(MigrationStep $step)
41
    {
42 1
        parent::execute($step);
43
44 1
        // BC: support 'mode'
45
        if (isset($step->dsl['repeat'])) {
46
            if (isset($step->dsl['over'])) {
47 1
                throw new InvalidStepDefinitionException("Invalid step definition: can not have both 'repeat' and 'over'");
48 1
            }
49
            if (isset($step->dsl['mode']) && $step->dsl['mode'] != 'repeat') {
50
                throw new InvalidStepDefinitionException("Invalid step definition: can not have different 'repeat' and 'mode'");
51 1
            }
52
            $action = 'repeat';
53
        } elseif (isset($step->dsl['over'])) {
54 1
            if (isset($step->dsl['mode']) && $step->dsl['mode'] != 'iterate') {
55 1
                throw new InvalidStepDefinitionException("Invalid step definition: can not have 'over' and 'mode' != 'iterate'");
56 1
            }
57
            $action = 'iterate';
58
        } elseif (isset($step->dsl['mode'])) {
59 1
            $action = $step->dsl['mode'];
60
        } else {
61
            throw new InvalidStepDefinitionException("Invalid step definition: missing 'repeat' or 'over' or 'mode'");
62
        }
63
64
        if (!isset($step->dsl['steps']) || !is_array($step->dsl['steps'])) {
65
            throw new InvalidStepDefinitionException("Invalid step definition: missing 'steps' or not an array");
66 1
        }
67
68
        if (!in_array($action, $this->supportedActions)) {
69
            throw new InvalidStepDefinitionException("Invalid step definition: value '$action' is not allowed for 'mode'");
70 1
        }
71
72
        $this->skipStepIfNeeded($step);
73 1
74
        // can not use keywords as method names
75 1
        $action = 'loop' . ucfirst($action);
76
77
        return $this->$action($step->dsl, $step->context);
78 1
    }
79
80 1
    protected function loopRepeat($dsl, $context)
81 1
    {
82
        $repeat = $this->resolveReference($dsl['repeat']);
83
        if ((!is_int($repeat) && !ctype_digit($repeat)) || $repeat < 0) {
84
            throw new InvalidStepDefinitionException("Invalid step definition: '$repeat' is not a positive integer");
85 1
        }
86
87 1
        $stepExecutors = $this->validateSteps($dsl);
88 1
89
        $this->loopResolver->beginLoop();
90
        $result = null;
91 1
92
        // NB: we are *not* firing events for each pass of the loop... it might be worth making that optionally happen ?
93 1
        for ($i = 0; $i < $repeat; $i++) {
94
95
            $this->loopResolver->loopStep();
96 1
97 1
            try {
98 1
                foreach ($dsl['steps'] as $j => $stepDef) {
99 1
                    $type = $stepDef['type'];
100
                    unset($stepDef['type']);
101 1
                    $subStep = new MigrationStep($type, $stepDef, array_merge($context, array()));
102
                    try {
103
                        $result = $stepExecutors[$j]->execute($subStep);
104
                    } catch (MigrationStepSkippedException $e) {
105
                        // all ok, continue the loop
106
                    } catch (LoopContinueException $e) {
107
                        // all ok, move to the next iteration
108
                        break;
109
                    }
110
                }
111
            } catch (LoopBreakException $e) {
112
                // all ok, exit the loop
113
                break;
114
            }
115 1
        }
116 1
117
        $this->loopResolver->endLoop();
118
        return $result;
119 1
    }
120
121 1
    protected function loopIterate($dsl, $context)
122
    {
123 1
        $stepExecutors = $this->validateSteps($dsl);
124
125 1
        $over = $this->resolveReference($dsl['over']);
126 1
127
        $this->loopResolver->beginLoop();
128 1
        $result = null;
129 1
130
        foreach ($over as $key => $value) {
131
            $this->loopResolver->loopStep($key, $value);
132 1
133 1
            try {
134 1
                foreach ($dsl['steps'] as $j => $stepDef) {
135 1
                    $type = $stepDef['type'];
136
                    unset($stepDef['type']);
137 1
                    $subStep = new MigrationStep($type, $stepDef, array_merge($context, array()));
138
                    try {
139
                        $result = $stepExecutors[$j]->execute($subStep);
140
                    } catch (MigrationStepSkippedException $e) {
141
                        // all ok, continue the loop
142
                    } catch (LoopContinueException $e) {
143
                        // all ok, move to the next iteration
144
                        break;
145
                    }
146
                }
147
            } catch (LoopBreakException $e) {
148
                // all ok, exit the loop
149
                break;
150
            }
151 1
        }
152 1
153
        $this->loopResolver->endLoop();
154
        return $result;
155
    }
156
157
    /**
158
     * @param array $dsl
159
     * @param $context
160
     * @return void
161
     * @throws LoopBreakException
162
     */
163
    protected function loopBreak($dsl, $context)
164
    {
165
        $message = isset($dsl['message']) ? $dsl['message'] : '';
166
167
        throw new LoopBreakException($message);
168
    }
169
170
    /**
171
     * @param array $dsl
172
     * @param $context
173
     * @return void
174
     * @throws LoopContinueException
175
     */
176
    protected function loopContinue($dsl, $context)
177
    {
178
        $message = isset($dsl['message']) ? $dsl['message'] : '';
179
180
        throw new LoopContinueException($message);
181 1
    }
182
183 1
    protected function validateSteps($dsl)
184
    {
185
        if (!isset($dsl['steps']) || !is_array($dsl['steps'])) {
186
            throw new InvalidStepDefinitionException("Invalid step definition: missing 'steps' or not an array");
187
        }
188 1
189
        // before engaging in the loop, check that all steps are valid
190 1
        $stepExecutors = array();
191 1
192
        foreach ($dsl['steps'] as $i => $stepDef) {
193 1
            $type = $stepDef['type'];
194
            try {
195
                $stepExecutors[$i] = $this->migrationService->getExecutor($type);
196
            } catch (\InvalidArgumentException $e) {
197
                throw new \InvalidArgumentException($e->getMessage() . " in sub-step of a loop step");
198 1
            }
199
        }
200
        return $stepExecutors;
201
    }
202
}
203