|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Kaliop\eZMigrationBundle\Core\Executor; |
|
4
|
|
|
|
|
5
|
|
|
use Kaliop\eZMigrationBundle\API\Value\MigrationStep; |
|
6
|
|
|
use Kaliop\eZMigrationBundle\API\ExecutorInterface; |
|
7
|
|
|
use Kaliop\eZMigrationBundle\API\Exception\MigrationAbortedException; |
|
8
|
|
|
use Kaliop\eZMigrationBundle\API\Exception\MigrationSuspendedException; |
|
9
|
|
|
use Kaliop\eZMigrationBundle\API\ReferenceResolverInterface; |
|
10
|
|
|
|
|
11
|
|
|
class MigrationExecutor extends AbstractExecutor |
|
12
|
|
|
{ |
|
13
|
|
|
protected $supportedStepTypes = array('migration'); |
|
14
|
|
|
protected $supportedActions = array('cancel', 'suspend', 'sleep'); |
|
15
|
|
|
|
|
16
|
|
|
protected $referenceMatcher; |
|
17
|
|
|
protected $referenceResolver; |
|
18
|
|
|
protected $contentManager; |
|
19
|
|
|
protected $locationManager; |
|
20
|
|
|
protected $contentTypeManager; |
|
21
|
|
|
|
|
22
|
|
|
public function __construct($referenceMatcher, ReferenceResolverInterface $referenceResolver, ExecutorInterface $contentManager, ExecutorInterface $locationManager, ExecutorInterface $contentTypeManager) |
|
23
|
|
|
{ |
|
24
|
|
|
$this->referenceMatcher = $referenceMatcher; |
|
25
|
|
|
$this->referenceResolver = $referenceResolver; |
|
26
|
|
|
$this->contentManager = $contentManager; |
|
27
|
|
|
$this->locationManager = $locationManager; |
|
28
|
|
|
$this->contentTypeManager = $contentTypeManager; |
|
29
|
|
|
} |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* @param MigrationStep $step |
|
33
|
|
|
* @return mixed |
|
34
|
|
|
* @throws \Exception |
|
35
|
|
|
*/ |
|
36
|
|
View Code Duplication |
public function execute(MigrationStep $step) |
|
|
|
|
|
|
37
|
|
|
{ |
|
38
|
|
|
parent::execute($step); |
|
39
|
|
|
|
|
40
|
|
|
if (!isset($step->dsl['mode'])) { |
|
41
|
|
|
throw new \Exception("Invalid step definition: missing 'mode'"); |
|
42
|
|
|
} |
|
43
|
|
|
|
|
44
|
|
|
$action = $step->dsl['mode']; |
|
45
|
|
|
|
|
46
|
|
|
if (!in_array($action, $this->supportedActions)) { |
|
47
|
|
|
throw new \Exception("Invalid step definition: value '$action' is not allowed for 'mode'"); |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
return $this->$action($step->dsl, $step->context); |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* @param array $dsl |
|
55
|
|
|
* @param array $context |
|
56
|
|
|
* @return true |
|
57
|
|
|
* @throws \Exception |
|
58
|
|
|
*/ |
|
59
|
|
|
protected function cancel($dsl, $context) |
|
|
|
|
|
|
60
|
|
|
{ |
|
61
|
|
|
$message = isset($dsl['message']) ? $dsl['message'] : ''; |
|
62
|
|
|
|
|
63
|
|
|
if (isset($dsl['if'])) { |
|
64
|
|
|
if (!$this->matchConditions($dsl['if'])) { |
|
65
|
|
|
// q: return timestamp, matched condition or ... ? |
|
66
|
|
|
return true; |
|
67
|
|
|
} |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
throw new MigrationAbortedException($message); |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* @param array $dsl |
|
75
|
|
|
* @param array $context |
|
76
|
|
|
* @return true |
|
77
|
|
|
* @throws \Exception |
|
78
|
|
|
*/ |
|
79
|
|
|
protected function suspend($dsl, $context) |
|
80
|
|
|
{ |
|
81
|
|
|
$message = isset($dsl['message']) ? $dsl['message'] : ''; |
|
82
|
|
|
|
|
83
|
|
|
if (!isset($dsl['until'])) { |
|
84
|
|
|
throw new \Exception("An until condition is required to suspend a migration"); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
if (isset($dsl['load'])) { |
|
88
|
|
|
$this->loadEntity($dsl['load'], $context); |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
if ($this->matchSuspend($dsl['until'])) { |
|
92
|
|
|
// the time has come to resume! |
|
93
|
|
|
// q: return timestamp, matched condition or ... ? |
|
94
|
|
|
return true; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
throw new MigrationSuspendedException($message); |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
protected function sleep($dsl, $context) |
|
|
|
|
|
|
101
|
|
|
{ |
|
102
|
|
|
if (!isset($dsl['seconds'])) { |
|
103
|
|
|
throw new \Exception("A 'seconds' element is required when putting a migration to sleep"); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
sleep($dsl['seconds']); |
|
107
|
|
|
return true; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
protected function loadEntity($dsl, $context) |
|
111
|
|
|
{ |
|
112
|
|
View Code Duplication |
if (!isset($dsl['type']) || !isset($dsl['match'])) { |
|
|
|
|
|
|
113
|
|
|
throw new \Exception("A 'type' and a 'match' are required to load entities when suspending a migration"); |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
$dsl['mode'] = 'load'; |
|
117
|
|
|
// be kind to users and allow them not to specify this explicitly |
|
118
|
|
|
if (isset($dsl['references'])) { |
|
119
|
|
|
foreach($dsl['references'] as &$refDef) { |
|
|
|
|
|
|
120
|
|
|
$refDef['overwrite'] = true; |
|
121
|
|
|
} |
|
122
|
|
|
} |
|
123
|
|
|
$step = new MigrationStep($dsl['type'], $dsl, $context); |
|
124
|
|
|
|
|
125
|
|
|
switch($dsl['type']) { |
|
126
|
|
|
case 'content': |
|
127
|
|
|
return $this->contentManager->execute($step); |
|
128
|
|
|
case 'location': |
|
129
|
|
|
return $this->locationManager->execute($step); |
|
130
|
|
|
case 'content_type': |
|
131
|
|
|
return $this->contentTypeManager->execute($step); |
|
132
|
|
|
} |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
protected function matchConditions($conditions) |
|
136
|
|
|
{ |
|
137
|
|
|
$match = $this->referenceMatcher->match($conditions); |
|
138
|
|
|
return reset($match); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
protected function matchSuspend($conditions) |
|
142
|
|
|
{ |
|
143
|
|
|
foreach ($conditions as $key => $values) { |
|
144
|
|
|
|
|
145
|
|
|
switch ($key) { |
|
146
|
|
|
case 'date': |
|
147
|
|
|
return time() >= $this->referenceResolver->resolveReference($values); |
|
148
|
|
|
|
|
149
|
|
|
case 'match': |
|
150
|
|
|
return $this->matchConditions($values); |
|
151
|
|
|
|
|
152
|
|
|
default: |
|
153
|
|
|
throw new \Exception("Unknown until condition: '$key' when suspending a migration ".var_export($conditions, true)); |
|
154
|
|
|
} |
|
155
|
|
|
} |
|
156
|
|
|
} |
|
157
|
|
|
} |
|
158
|
|
|
|
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.