|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Kaliop\eZMigrationBundle\Core\Executor; |
|
4
|
|
|
|
|
5
|
|
|
use Kaliop\eZMigrationBundle\API\Value\MigrationStep; |
|
6
|
|
|
use Kaliop\eZMigrationBundle\Core\ReferenceResolver\PrefixBasedResolverInterface; |
|
7
|
|
|
|
|
8
|
|
|
class FileExecutor extends AbstractExecutor |
|
9
|
|
|
{ |
|
10
|
|
|
use IgnorableStepExecutorTrait; |
|
11
|
|
|
|
|
12
|
|
|
protected $supportedStepTypes = array('file'); |
|
13
|
|
|
protected $supportedActions = array('load', 'save', 'copy', 'move', 'delete', 'append', 'prepend', 'exists'); |
|
14
|
|
|
|
|
15
|
|
|
/** @var PrefixBasedResolverInterface $referenceResolver */ |
|
16
|
|
|
protected $referenceResolver; |
|
17
|
|
|
|
|
18
|
73 |
|
public function __construct(PrefixBasedResolverInterface $referenceResolver) |
|
19
|
|
|
{ |
|
20
|
73 |
|
$this->referenceResolver = $referenceResolver; |
|
21
|
73 |
|
} |
|
22
|
|
|
|
|
23
|
|
|
/** |
|
24
|
|
|
* @param MigrationStep $step |
|
25
|
|
|
* @return mixed |
|
26
|
|
|
* @throws \Exception |
|
27
|
|
|
*/ |
|
28
|
2 |
View Code Duplication |
public function execute(MigrationStep $step) |
|
|
|
|
|
|
29
|
|
|
{ |
|
30
|
2 |
|
parent::execute($step); |
|
31
|
|
|
|
|
32
|
2 |
|
if (!isset($step->dsl['mode'])) { |
|
33
|
|
|
throw new \Exception("Invalid step definition: missing 'mode'"); |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
2 |
|
$action = $step->dsl['mode']; |
|
37
|
|
|
|
|
38
|
2 |
|
if (!in_array($action, $this->supportedActions)) { |
|
39
|
|
|
throw new \Exception("Invalid step definition: value '$action' is not allowed for 'mode'"); |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
2 |
|
$this->skipStepIfNeeded($step); |
|
43
|
|
|
|
|
44
|
2 |
|
return $this->$action($step->dsl, $step->context); |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* @param array $dsl |
|
49
|
|
|
* @param array $context |
|
50
|
|
|
* @return string |
|
51
|
|
|
* @throws \Exception |
|
52
|
|
|
*/ |
|
53
|
2 |
|
protected function load($dsl, $context) |
|
|
|
|
|
|
54
|
|
|
{ |
|
55
|
2 |
|
if (!isset($dsl['file'])) { |
|
56
|
|
|
throw new \Exception("Can not load file: name missing"); |
|
57
|
|
|
} |
|
58
|
2 |
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
59
|
2 |
|
if (!file_exists($fileName)) { |
|
60
|
|
|
throw new \Exception("Can not load '$fileName': file missing"); |
|
61
|
|
|
} |
|
62
|
|
|
|
|
63
|
2 |
|
$this->setReferences($fileName, $dsl); |
|
64
|
|
|
|
|
65
|
2 |
|
return file_get_contents($fileName); |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* @param array $dsl |
|
70
|
|
|
* @param array $context |
|
71
|
|
|
* @return string |
|
72
|
|
|
* @throws \Exception |
|
73
|
|
|
*/ |
|
74
|
1 |
|
protected function exists($dsl, $context) |
|
|
|
|
|
|
75
|
|
|
{ |
|
76
|
1 |
|
if (!isset($dsl['file'])) { |
|
77
|
|
|
throw new \Exception("Can not check for existence of file: name missing"); |
|
78
|
|
|
} |
|
79
|
1 |
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
80
|
|
|
|
|
81
|
1 |
|
$exists = file_exists($fileName); |
|
82
|
|
|
|
|
83
|
1 |
|
if (array_key_exists('references', $dsl)) { |
|
84
|
1 |
|
foreach ($dsl['references'] as $reference) { |
|
85
|
1 |
|
switch ($reference['attribute']) { |
|
86
|
1 |
|
case 'exists': |
|
87
|
1 |
|
$overwrite = false; |
|
88
|
1 |
|
if (isset($reference['overwrite'])) { |
|
89
|
1 |
|
$overwrite = $reference['overwrite']; |
|
90
|
|
|
} |
|
91
|
1 |
|
$this->referenceResolver->addReference($reference['identifier'], $exists, $overwrite); |
|
|
|
|
|
|
92
|
1 |
|
break; |
|
93
|
|
|
} |
|
94
|
|
|
} |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
1 |
|
return $exists; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* @param array $dsl |
|
102
|
|
|
* @param array $context |
|
103
|
|
|
* @return int |
|
104
|
|
|
* @throws \Exception |
|
105
|
|
|
*/ |
|
106
|
1 |
|
protected function save($dsl, $context) |
|
107
|
|
|
{ |
|
108
|
1 |
View Code Duplication |
if (!isset($dsl['file']) || (!isset($dsl['body']) && !isset($dsl['template']))) { |
|
|
|
|
|
|
109
|
|
|
throw new \Exception("Can not save file: name or body or template missing"); |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
1 |
View Code Duplication |
if (is_string($dsl['body'])) { |
|
|
|
|
|
|
113
|
1 |
|
$contents = $this->resolveReferencesInText($dsl['body']); |
|
114
|
|
|
} elseif (is_string($dsl['template'])) { |
|
115
|
|
|
$path = $this->referenceResolver->resolveReference($dsl['template']); |
|
116
|
|
|
// we use the same logic as for the image/file fields in content: look up file 1st relative to the migration |
|
117
|
|
|
$template = dirname($context['path']) . '/' . $path; |
|
118
|
|
|
if (!is_file($template)) { |
|
119
|
|
|
$template = $path; |
|
120
|
1 |
|
} |
|
121
|
|
|
$contents = $this->resolveReferencesInText(file_get_contents($template)); |
|
122
|
1 |
|
} else { |
|
123
|
1 |
|
throw new \Exception("Can not save file: either body or template tag must be a string"); |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
127
|
1 |
|
|
|
128
|
|
|
$overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false; |
|
129
|
1 |
|
if (!$overwrite && file_exists($fileName)) { |
|
|
|
|
|
|
130
|
|
|
throw new \Exception("Can not save file '$fileName: file already exists"); |
|
131
|
1 |
|
} |
|
132
|
|
|
|
|
133
|
|
|
$return = file_put_contents($fileName, $contents); |
|
134
|
|
|
|
|
135
|
|
|
$this->setReferences($fileName, $dsl); |
|
136
|
|
|
|
|
137
|
|
|
return $return; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
1 |
|
/** |
|
141
|
|
|
* @param array $dsl |
|
142
|
1 |
|
* @param array $context |
|
143
|
|
|
* @return int |
|
144
|
|
|
* @throws \Exception |
|
145
|
|
|
*/ |
|
146
|
1 |
|
protected function append($dsl, $context) |
|
147
|
1 |
|
{ |
|
148
|
|
View Code Duplication |
if (!isset($dsl['file']) || (!isset($dsl['body']) && !isset($dsl['template']))) { |
|
|
|
|
|
|
149
|
|
|
throw new \Exception("Can not append to file: name or body or template missing"); |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
View Code Duplication |
if (is_string($dsl['body'])) { |
|
|
|
|
|
|
153
|
|
|
$contents = $this->resolveReferencesInText($dsl['body']); |
|
154
|
1 |
|
} elseif (is_string($dsl['template'])) { |
|
155
|
|
|
$path = $this->referenceResolver->resolveReference($dsl['template']); |
|
156
|
1 |
|
// we use the same logic as for the image/file fields in content: look up file 1st relative to the migration |
|
157
|
|
|
$template = dirname($context['path']) . '/' . $path; |
|
158
|
1 |
|
if (!is_file($template)) { |
|
159
|
|
|
$template = $path; |
|
160
|
1 |
|
} |
|
161
|
|
|
$contents = $this->resolveReferencesInText(file_get_contents($template)); |
|
162
|
|
|
} else { |
|
163
|
|
|
throw new \Exception("Can not append to file: either body or template tag must be a string"); |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
167
|
|
|
|
|
168
|
|
|
$return = file_put_contents($fileName, $contents, FILE_APPEND); |
|
169
|
|
|
|
|
170
|
|
|
$this->setReferences($fileName, $dsl); |
|
171
|
|
|
|
|
172
|
|
|
return $return; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* @param array $dsl |
|
177
|
|
|
* @param array $context |
|
178
|
|
|
* @return int |
|
179
|
|
|
* @throws \Exception |
|
180
|
|
|
*/ |
|
181
|
|
|
protected function prepend($dsl, $context) |
|
182
|
|
|
{ |
|
183
|
|
View Code Duplication |
if (!isset($dsl['file']) || (!isset($dsl['body']) && !isset($dsl['template']))) { |
|
|
|
|
|
|
184
|
|
|
throw new \Exception("Can not prepend to file: name or body or template missing"); |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
|
View Code Duplication |
if (is_string($dsl['body'])) { |
|
|
|
|
|
|
188
|
|
|
$contents = $this->resolveReferencesInText($dsl['body']); |
|
189
|
|
|
} elseif (is_string($dsl['template'])) { |
|
190
|
|
|
$path = $this->referenceResolver->resolveReference($dsl['template']); |
|
191
|
|
|
// we use the same logic as for the image/file fields in content: look up file 1st relative to the migration |
|
192
|
|
|
$template = dirname($context['path']) . '/' . $path; |
|
193
|
|
|
if (!is_file($template)) { |
|
194
|
|
|
$template = $path; |
|
195
|
|
|
} |
|
196
|
|
|
$contents = $this->resolveReferencesInText(file_get_contents($template)); |
|
197
|
|
|
} else { |
|
198
|
|
|
throw new \Exception("Can not append to file: either body or template tag must be a string"); |
|
199
|
|
|
} |
|
200
|
|
|
|
|
201
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
202
|
1 |
|
|
|
203
|
|
|
if (file_exists($fileName)) { |
|
204
|
1 |
|
$contents .= file_get_contents($fileName); |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
$return = file_put_contents($fileName, $contents); |
|
208
|
1 |
|
|
|
209
|
1 |
|
$this->setReferences($fileName, $dsl); |
|
210
|
|
|
|
|
211
|
|
|
return $return; |
|
212
|
|
|
} |
|
213
|
1 |
|
|
|
214
|
|
|
/** |
|
215
|
1 |
|
* @param array $dsl |
|
216
|
1 |
|
* @param array $context |
|
217
|
1 |
|
* @return true |
|
218
|
|
|
* @throws \Exception |
|
219
|
|
|
*/ |
|
220
|
|
View Code Duplication |
protected function copy($dsl, $context) |
|
|
|
|
|
|
221
|
1 |
|
{ |
|
222
|
|
|
if (!isset($dsl['from']) || !isset($dsl['to'])) { |
|
223
|
|
|
throw new \Exception("Can not copy file: from or to missing"); |
|
224
|
|
|
} |
|
225
|
1 |
|
|
|
226
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['from']); |
|
227
|
|
|
if (!file_exists($fileName)) { |
|
228
|
|
|
throw new \Exception("Can not copy file '$fileName': file missing"); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
$this->setReferences($fileName, $dsl); |
|
232
|
|
|
|
|
233
|
|
|
$to = $this->referenceResolver->resolveReference($dsl['to']); |
|
234
|
1 |
|
$overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false; |
|
235
|
|
|
if (!$overwrite && file_exists($to)) { |
|
236
|
1 |
|
throw new \Exception("Can not copy file to '$to: file already exists"); |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
if (!copy($fileName, $to)) { |
|
240
|
1 |
|
throw new \Exception("Can not copy file '$fileName' to '$to': operation failed"); |
|
241
|
1 |
|
} |
|
242
|
|
|
|
|
243
|
|
|
return true; |
|
244
|
|
|
} |
|
245
|
1 |
|
|
|
246
|
|
|
/** |
|
247
|
1 |
|
* @param array $dsl |
|
248
|
1 |
|
* @param array $context |
|
249
|
1 |
|
* @return true |
|
250
|
|
|
* @throws \Exception |
|
251
|
|
|
*/ |
|
252
|
|
View Code Duplication |
protected function move($dsl, $context) |
|
|
|
|
|
|
253
|
1 |
|
{ |
|
254
|
|
|
if (!isset($dsl['from']) || !isset($dsl['to'])) { |
|
255
|
|
|
throw new \Exception("Can not move file: from or to missing"); |
|
256
|
|
|
} |
|
257
|
1 |
|
|
|
258
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['from']); |
|
259
|
|
|
if (!file_exists($fileName)) { |
|
260
|
|
|
throw new \Exception("Can not move file '$fileName': file missing"); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
$this->setReferences($fileName, $dsl); |
|
264
|
|
|
|
|
265
|
|
|
$to = $this->referenceResolver->resolveReference($dsl['to']); |
|
266
|
1 |
|
$overwrite = isset($dsl['overwrite']) ? $overwrite = $dsl['overwrite'] : false; |
|
267
|
|
|
if (!$overwrite && file_exists($to)) { |
|
268
|
1 |
|
throw new \Exception("Can not move to '$to': file already exists"); |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
if (!rename($fileName, $to)) { |
|
272
|
1 |
|
throw new \Exception("Can not move file '$fileName': operation failed"); |
|
273
|
1 |
|
} |
|
274
|
|
|
|
|
275
|
|
|
return true; |
|
276
|
|
|
} |
|
277
|
1 |
|
|
|
278
|
|
|
/** |
|
279
|
1 |
|
* @param array $dsl |
|
280
|
|
|
* @param array $context |
|
281
|
|
|
* @return true |
|
282
|
|
|
* @throws \Exception |
|
283
|
1 |
|
*/ |
|
284
|
|
|
protected function delete($dsl, $context) |
|
|
|
|
|
|
285
|
|
|
{ |
|
286
|
2 |
|
if (!isset($dsl['file'])) { |
|
287
|
|
|
throw new \Exception("Can not delete file: name missing"); |
|
288
|
2 |
|
} |
|
289
|
1 |
|
|
|
290
|
|
|
$fileName = $this->referenceResolver->resolveReference($dsl['file']); |
|
291
|
|
|
if (!file_exists($fileName)) { |
|
292
|
2 |
|
throw new \Exception("Can not move delete '$fileName': file missing"); |
|
293
|
2 |
|
} |
|
294
|
|
|
|
|
295
|
2 |
|
$this->setReferences($fileName, $dsl); |
|
296
|
|
|
|
|
297
|
|
|
if (!unlink($fileName)) { |
|
298
|
|
|
throw new \Exception("Can not delete file '$fileName': operation failed"); |
|
299
|
2 |
|
} |
|
300
|
2 |
|
|
|
301
|
2 |
|
return true; |
|
302
|
2 |
|
} |
|
303
|
2 |
|
|
|
304
|
1 |
|
protected function setReferences($fileName, $dsl) |
|
305
|
1 |
|
{ |
|
306
|
1 |
|
if (!array_key_exists('references', $dsl)) { |
|
307
|
1 |
|
return false; |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
1 |
|
clearstatcache(true, $fileName); |
|
311
|
|
|
$stats = stat($fileName); |
|
312
|
|
|
|
|
313
|
1 |
|
if (!$stats) { |
|
|
|
|
|
|
314
|
1 |
|
throw new \Exception("Can not set references for file '$fileName': stat failed"); |
|
315
|
1 |
|
} |
|
316
|
1 |
|
|
|
317
|
|
|
foreach ($dsl['references'] as $reference) { |
|
318
|
|
|
switch ($reference['attribute']) { |
|
319
|
1 |
|
case 'body': |
|
320
|
1 |
|
$value = file_get_contents($fileName); |
|
321
|
1 |
|
break; |
|
322
|
|
|
case 'size': |
|
323
|
|
|
$value = $stats[7]; |
|
324
|
|
|
break; |
|
325
|
|
|
case 'uid': |
|
326
|
2 |
|
$value = $stats[4]; |
|
327
|
2 |
|
break; |
|
328
|
|
|
case 'gid': |
|
329
|
|
|
$value = $stats[5]; |
|
330
|
2 |
|
break; |
|
331
|
|
|
case 'atime': |
|
332
|
|
|
$value = $stats[8]; |
|
333
|
2 |
|
break; |
|
334
|
|
|
case 'mtime': |
|
335
|
|
|
$value = $stats[9]; |
|
336
|
|
|
break; |
|
337
|
|
|
case 'ctime': |
|
338
|
|
|
$value = $stats[10]; |
|
339
|
|
|
break; |
|
340
|
|
|
default: |
|
341
|
|
|
throw new \InvalidArgumentException('File executor does not support setting references for attribute ' . $reference['attribute']); |
|
342
|
1 |
|
} |
|
343
|
|
|
|
|
344
|
|
|
$overwrite = false; |
|
345
|
1 |
|
if (isset($reference['overwrite'])) { |
|
346
|
|
|
$overwrite = $reference['overwrite']; |
|
347
|
1 |
|
} |
|
348
|
|
|
$this->referenceResolver->addReference($reference['identifier'], $value, $overwrite); |
|
|
|
|
|
|
349
|
1 |
|
} |
|
350
|
|
|
|
|
351
|
1 |
|
return true; |
|
352
|
1 |
|
} |
|
353
|
1 |
|
|
|
354
|
1 |
|
/** |
|
355
|
|
|
* Replaces any references inside a string |
|
356
|
|
|
* |
|
357
|
|
|
* @param string $text |
|
358
|
1 |
|
* @return string |
|
359
|
|
|
*/ |
|
360
|
|
View Code Duplication |
protected function resolveReferencesInText($text) |
|
|
|
|
|
|
361
|
|
|
{ |
|
362
|
|
|
// we need to alter the regexp we get from the resolver, as it will be used to match parts of text, not the whole string |
|
363
|
|
|
$regexp = substr($this->referenceResolver->getRegexp(), 1, -1); |
|
364
|
|
|
// NB: here we assume that all regexp resolvers give us a regexp with a very specific format... |
|
365
|
|
|
$regexp = '/\[' . preg_replace(array('/^\^/'), array('', ''), $regexp) . '[^]]+\]/'; |
|
366
|
|
|
|
|
367
|
|
|
$count = preg_match_all($regexp, $text, $matches); |
|
368
|
|
|
// $matches[0][] will have the matched full string eg.: [reference:example_reference] |
|
369
|
|
|
if ($count) { |
|
370
|
|
|
foreach ($matches[0] as $referenceIdentifier) { |
|
371
|
|
|
$reference = $this->referenceResolver->getReferenceValue(substr($referenceIdentifier, 1, -1)); |
|
372
|
|
|
$text = str_replace($referenceIdentifier, $reference, $text); |
|
373
|
|
|
} |
|
374
|
|
|
} |
|
375
|
|
|
|
|
376
|
|
|
return $text; |
|
377
|
|
|
} |
|
378
|
|
|
} |
|
379
|
|
|
|
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.