|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* TechDivision\Import\Subjects\AbstractSubject |
|
5
|
|
|
* |
|
6
|
|
|
* NOTICE OF LICENSE |
|
7
|
|
|
* |
|
8
|
|
|
* This source file is subject to the Open Software License (OSL 3.0) |
|
9
|
|
|
* that is available through the world-wide-web at this URL: |
|
10
|
|
|
* http://opensource.org/licenses/osl-3.0.php |
|
11
|
|
|
* |
|
12
|
|
|
* PHP version 5 |
|
13
|
|
|
* |
|
14
|
|
|
* @author Tim Wagner <[email protected]> |
|
15
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
|
16
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
|
17
|
|
|
* @link https://github.com/techdivision/import |
|
18
|
|
|
* @link http://www.techdivision.com |
|
19
|
|
|
*/ |
|
20
|
|
|
|
|
21
|
|
|
namespace TechDivision\Import\Subjects; |
|
22
|
|
|
|
|
23
|
|
|
use Psr\Log\LoggerInterface; |
|
24
|
|
|
use TechDivision\Import\Utils\ScopeKeys; |
|
25
|
|
|
use TechDivision\Import\Utils\LoggerKeys; |
|
26
|
|
|
use TechDivision\Import\Utils\ColumnKeys; |
|
27
|
|
|
use TechDivision\Import\Utils\MemberNames; |
|
28
|
|
|
use TechDivision\Import\Utils\RegistryKeys; |
|
29
|
|
|
use TechDivision\Import\Utils\Generators\GeneratorInterface; |
|
30
|
|
|
use TechDivision\Import\Services\RegistryProcessor; |
|
31
|
|
|
use TechDivision\Import\Callbacks\CallbackInterface; |
|
32
|
|
|
use TechDivision\Import\Observers\ObserverInterface; |
|
33
|
|
|
use TechDivision\Import\Adapter\ImportAdapterInterface; |
|
34
|
|
|
use TechDivision\Import\Exceptions\WrappedColumnException; |
|
35
|
|
|
use TechDivision\Import\Services\RegistryProcessorInterface; |
|
36
|
|
|
use TechDivision\Import\Configuration\SubjectConfigurationInterface; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* An abstract subject implementation. |
|
40
|
|
|
* |
|
41
|
|
|
* @author Tim Wagner <[email protected]> |
|
42
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
|
43
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
|
44
|
|
|
* @link https://github.com/techdivision/import |
|
45
|
|
|
* @link http://www.techdivision.com |
|
46
|
|
|
*/ |
|
47
|
|
|
abstract class AbstractSubject implements SubjectInterface |
|
48
|
|
|
{ |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* The trait that provides basic filesystem handling functionality. |
|
52
|
|
|
* |
|
53
|
|
|
* @var TechDivision\Import\Subjects\FilesystemTrait |
|
54
|
|
|
*/ |
|
55
|
|
|
use FilesystemTrait; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* The import adapter instance. |
|
59
|
|
|
* |
|
60
|
|
|
* @var \TechDivision\Import\Adapter\AdapterInterface |
|
61
|
|
|
*/ |
|
62
|
|
|
protected $importAdapter; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* The system configuration. |
|
66
|
|
|
* |
|
67
|
|
|
* @var \TechDivision\Import\Configuration\SubjectConfigurationInterface |
|
68
|
|
|
*/ |
|
69
|
|
|
protected $configuration; |
|
70
|
|
|
|
|
71
|
|
|
/** |
|
72
|
|
|
* The array with the system logger instances. |
|
73
|
|
|
* |
|
74
|
|
|
* @var array |
|
75
|
|
|
*/ |
|
76
|
|
|
protected $systemLoggers = array(); |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* The RegistryProcessor instance to handle running threads. |
|
80
|
|
|
* |
|
81
|
|
|
* @var \TechDivision\Import\Services\RegistryProcessorInterface |
|
82
|
|
|
*/ |
|
83
|
|
|
protected $registryProcessor; |
|
84
|
|
|
|
|
85
|
|
|
/** |
|
86
|
|
|
* The actions unique serial. |
|
87
|
|
|
* |
|
88
|
|
|
* @var string |
|
89
|
|
|
*/ |
|
90
|
|
|
protected $serial; |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* The name of the file to be imported. |
|
94
|
|
|
* |
|
95
|
|
|
* @var string |
|
96
|
|
|
*/ |
|
97
|
|
|
protected $filename; |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* Array with the subject's observers. |
|
101
|
|
|
* |
|
102
|
|
|
* @var array |
|
103
|
|
|
*/ |
|
104
|
|
|
protected $observers = array(); |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Array with the subject's callbacks. |
|
108
|
|
|
* |
|
109
|
|
|
* @var array |
|
110
|
|
|
*/ |
|
111
|
|
|
protected $callbacks = array(); |
|
112
|
|
|
|
|
113
|
|
|
/** |
|
114
|
|
|
* The subject's callback mappings. |
|
115
|
|
|
* |
|
116
|
|
|
* @var array |
|
117
|
|
|
*/ |
|
118
|
|
|
protected $callbackMappings = array(); |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* Contain's the column names from the header line. |
|
122
|
|
|
* |
|
123
|
|
|
* @var array |
|
124
|
|
|
*/ |
|
125
|
|
|
protected $headers = array(); |
|
126
|
|
|
|
|
127
|
|
|
/** |
|
128
|
|
|
* The actual line number. |
|
129
|
|
|
* |
|
130
|
|
|
* @var integer |
|
131
|
|
|
*/ |
|
132
|
|
|
protected $lineNumber = 0; |
|
133
|
|
|
|
|
134
|
|
|
/** |
|
135
|
|
|
* The actual operation name. |
|
136
|
|
|
* |
|
137
|
|
|
* @var string |
|
138
|
|
|
*/ |
|
139
|
|
|
protected $operationName ; |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* The flag that stop's overserver execution on the actual row. |
|
143
|
|
|
* |
|
144
|
|
|
* @var boolean |
|
145
|
|
|
*/ |
|
146
|
|
|
protected $skipRow = false; |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* The available root categories. |
|
150
|
|
|
* |
|
151
|
|
|
* @var array |
|
152
|
|
|
*/ |
|
153
|
|
|
protected $rootCategories = array(); |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* The Magento configuration. |
|
157
|
|
|
* |
|
158
|
|
|
* @var array |
|
159
|
|
|
*/ |
|
160
|
|
|
protected $coreConfigData = array(); |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* The available stores. |
|
164
|
|
|
* |
|
165
|
|
|
* @var array |
|
166
|
|
|
*/ |
|
167
|
|
|
protected $stores = array(); |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* The available websites. |
|
171
|
|
|
* |
|
172
|
|
|
* @var array |
|
173
|
|
|
*/ |
|
174
|
|
|
protected $storeWebsites = array(); |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* The default store. |
|
178
|
|
|
* |
|
179
|
|
|
* @var array |
|
180
|
|
|
*/ |
|
181
|
|
|
protected $defaultStore; |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* The store view code the create the product/attributes for. |
|
185
|
|
|
* |
|
186
|
|
|
* @var string |
|
187
|
|
|
*/ |
|
188
|
|
|
protected $storeViewCode; |
|
189
|
|
|
|
|
190
|
|
|
/** |
|
191
|
|
|
* The UID generator for the core config data. |
|
192
|
|
|
* |
|
193
|
|
|
* @var \TechDivision\Import\Utils\Generators\GeneratorInterface |
|
194
|
|
|
*/ |
|
195
|
|
|
protected $coreConfigDataUidGenerator; |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* The actual row. |
|
199
|
|
|
* |
|
200
|
|
|
* @var array |
|
201
|
|
|
*/ |
|
202
|
|
|
protected $row = array(); |
|
203
|
|
|
|
|
204
|
|
|
/** |
|
205
|
|
|
* Initialize the subject instance. |
|
206
|
|
|
* |
|
207
|
|
|
* @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor The registry processor instance |
|
208
|
|
|
* @param \TechDivision\Import\Utils\Generators\GeneratorInterface $coreConfigDataUidGenerator The UID generator for the core config data |
|
209
|
|
|
* @param array $systemLoggers The array with the system loggers instances |
|
210
|
|
|
*/ |
|
211
|
75 |
|
public function __construct( |
|
212
|
|
|
RegistryProcessorInterface $registryProcessor, |
|
213
|
|
|
GeneratorInterface $coreConfigDataUidGenerator, |
|
214
|
|
|
array $systemLoggers |
|
215
|
|
|
) { |
|
216
|
75 |
|
$this->systemLoggers = $systemLoggers; |
|
217
|
75 |
|
$this->registryProcessor = $registryProcessor; |
|
218
|
75 |
|
$this->coreConfigDataUidGenerator = $coreConfigDataUidGenerator; |
|
219
|
75 |
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* Return's the default callback mappings. |
|
223
|
|
|
* |
|
224
|
|
|
* @return array The default callback mappings |
|
225
|
|
|
*/ |
|
226
|
1 |
|
public function getDefaultCallbackMappings() |
|
227
|
|
|
{ |
|
228
|
1 |
|
return array(); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
/** |
|
232
|
|
|
* Return's the actual row. |
|
233
|
|
|
* |
|
234
|
|
|
* @return array The actual row |
|
235
|
|
|
*/ |
|
236
|
4 |
|
public function getRow() |
|
237
|
|
|
{ |
|
238
|
4 |
|
return $this->row; |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
/** |
|
242
|
|
|
* Stop's observer execution on the actual row. |
|
243
|
|
|
* |
|
244
|
|
|
* @return void |
|
245
|
|
|
*/ |
|
246
|
1 |
|
public function skipRow() |
|
247
|
|
|
{ |
|
248
|
1 |
|
$this->skipRow = true; |
|
249
|
1 |
|
} |
|
250
|
|
|
|
|
251
|
|
|
/** |
|
252
|
|
|
* Return's the actual line number. |
|
253
|
|
|
* |
|
254
|
|
|
* @return integer The line number |
|
255
|
|
|
*/ |
|
256
|
8 |
|
public function getLineNumber() |
|
257
|
|
|
{ |
|
258
|
8 |
|
return $this->lineNumber; |
|
259
|
|
|
} |
|
260
|
|
|
|
|
261
|
|
|
/** |
|
262
|
|
|
* Return's the actual operation name. |
|
263
|
|
|
* |
|
264
|
|
|
* @return string |
|
265
|
|
|
*/ |
|
266
|
1 |
|
public function getOperationName() |
|
267
|
|
|
{ |
|
268
|
1 |
|
return $this->operationName; |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
/** |
|
272
|
|
|
* Set's the array containing header row. |
|
273
|
|
|
* |
|
274
|
|
|
* @param array $headers The array with the header row |
|
275
|
|
|
* |
|
276
|
|
|
* @return void |
|
277
|
|
|
*/ |
|
278
|
9 |
|
public function setHeaders(array $headers) |
|
279
|
|
|
{ |
|
280
|
9 |
|
$this->headers = $headers; |
|
281
|
9 |
|
} |
|
282
|
|
|
|
|
283
|
|
|
/** |
|
284
|
|
|
* Return's the array containing header row. |
|
285
|
|
|
* |
|
286
|
|
|
* @return array The array with the header row |
|
287
|
|
|
*/ |
|
288
|
2 |
|
public function getHeaders() |
|
289
|
|
|
{ |
|
290
|
2 |
|
return $this->headers; |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
/** |
|
294
|
|
|
* Queries whether or not the header with the passed name is available. |
|
295
|
|
|
* |
|
296
|
|
|
* @param string $name The header name to query |
|
297
|
|
|
* |
|
298
|
|
|
* @return boolean TRUE if the header is available, else FALSE |
|
299
|
|
|
*/ |
|
300
|
8 |
|
public function hasHeader($name) |
|
301
|
|
|
{ |
|
302
|
8 |
|
return isset($this->headers[$name]); |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
/** |
|
306
|
|
|
* Return's the header value for the passed name. |
|
307
|
|
|
* |
|
308
|
|
|
* @param string $name The name of the header to return the value for |
|
309
|
|
|
* |
|
310
|
|
|
* @return mixed The header value |
|
311
|
|
|
* \InvalidArgumentException Is thrown, if the header with the passed name is NOT available |
|
312
|
|
|
*/ |
|
313
|
7 |
|
public function getHeader($name) |
|
314
|
|
|
{ |
|
315
|
|
|
|
|
316
|
|
|
// query whether or not, the header is available |
|
317
|
7 |
|
if (isset($this->headers[$name])) { |
|
318
|
6 |
|
return $this->headers[$name]; |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
// throw an exception, if not |
|
322
|
1 |
|
throw new \InvalidArgumentException(sprintf('Header %s is not available', $name)); |
|
323
|
|
|
} |
|
324
|
|
|
|
|
325
|
|
|
/** |
|
326
|
|
|
* Add's the header with the passed name and position, if not NULL. |
|
327
|
|
|
* |
|
328
|
|
|
* @param string $name The header name to add |
|
329
|
|
|
* |
|
330
|
|
|
* @return integer The new headers position |
|
331
|
|
|
*/ |
|
332
|
2 |
|
public function addHeader($name) |
|
333
|
|
|
{ |
|
334
|
|
|
|
|
335
|
|
|
// add the header |
|
336
|
2 |
|
$this->headers[$name] = $position = sizeof($this->headers); |
|
337
|
|
|
|
|
338
|
|
|
// return the new header's position |
|
339
|
2 |
|
return $position; |
|
340
|
|
|
} |
|
341
|
|
|
|
|
342
|
|
|
/** |
|
343
|
|
|
* Query whether or not a value for the column with the passed name exists. |
|
344
|
|
|
* |
|
345
|
|
|
* @param string $name The column name to query for a valid value |
|
346
|
|
|
* |
|
347
|
|
|
* @return boolean TRUE if the value is set, else FALSE |
|
348
|
|
|
*/ |
|
349
|
2 |
View Code Duplication |
public function hasValue($name) |
|
|
|
|
|
|
350
|
|
|
{ |
|
351
|
|
|
|
|
352
|
|
|
// query whether or not the header is available |
|
353
|
2 |
|
if ($this->hasHeader($name)) { |
|
354
|
|
|
// load the key for the row |
|
355
|
1 |
|
$headerValue = $this->getHeader($name); |
|
356
|
|
|
|
|
357
|
|
|
// query whether the rows column has a vaild value |
|
358
|
1 |
|
return (isset($this->row[$headerValue]) && $this->row[$headerValue] != ''); |
|
359
|
|
|
} |
|
360
|
|
|
|
|
361
|
|
|
// return FALSE if not |
|
362
|
1 |
|
return false; |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
/** |
|
366
|
|
|
* Set the value in the passed column name. |
|
367
|
|
|
* |
|
368
|
|
|
* @param string $name The column name to set the value for |
|
369
|
|
|
* @param mixed $value The value to set |
|
370
|
|
|
* |
|
371
|
|
|
* @return void |
|
372
|
|
|
*/ |
|
373
|
2 |
|
public function setValue($name, $value) |
|
374
|
|
|
{ |
|
375
|
2 |
|
$this->row[$this->getHeader($name)] = $value; |
|
376
|
2 |
|
} |
|
377
|
|
|
|
|
378
|
|
|
/** |
|
379
|
|
|
* Resolve's the value with the passed colum name from the actual row. If a callback will |
|
380
|
|
|
* be passed, the callback will be invoked with the found value as parameter. If |
|
381
|
|
|
* the value is NULL or empty, the default value will be returned. |
|
382
|
|
|
* |
|
383
|
|
|
* @param string $name The name of the column to return the value for |
|
384
|
|
|
* @param mixed|null $default The default value, that has to be returned, if the row's value is empty |
|
385
|
|
|
* @param callable|null $callback The callback that has to be invoked on the value, e. g. to format it |
|
386
|
|
|
* |
|
387
|
|
|
* @return mixed|null The, almost formatted, value |
|
388
|
|
|
*/ |
|
389
|
5 |
View Code Duplication |
public function getValue($name, $default = null, callable $callback = null) |
|
|
|
|
|
|
390
|
|
|
{ |
|
391
|
|
|
|
|
392
|
|
|
// initialize the value |
|
393
|
5 |
|
$value = null; |
|
394
|
|
|
|
|
395
|
|
|
// query whether or not the header is available |
|
396
|
5 |
|
if ($this->hasHeader($name)) { |
|
397
|
|
|
// load the header value |
|
398
|
4 |
|
$headerValue = $this->getHeader($name); |
|
399
|
|
|
// query wheter or not, the value with the requested key is available |
|
400
|
4 |
|
if ((isset($this->row[$headerValue]) && $this->row[$headerValue] != '')) { |
|
401
|
4 |
|
$value = $this->row[$headerValue]; |
|
402
|
|
|
} |
|
403
|
|
|
} |
|
404
|
|
|
|
|
405
|
|
|
// query whether or not, a callback has been passed |
|
406
|
5 |
|
if ($value != null && is_callable($callback)) { |
|
407
|
1 |
|
$value = call_user_func($callback, $value); |
|
408
|
|
|
} |
|
409
|
|
|
|
|
410
|
|
|
// query whether or not |
|
411
|
5 |
|
if ($value == null && $default !== null) { |
|
412
|
1 |
|
$value = $default; |
|
413
|
|
|
} |
|
414
|
|
|
|
|
415
|
|
|
// return the value |
|
416
|
5 |
|
return $value; |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
/** |
|
420
|
|
|
* Tries to format the passed value to a valid date with format 'Y-m-d H:i:s'. |
|
421
|
|
|
* If the passed value is NOT a valid date, NULL will be returned. |
|
422
|
|
|
* |
|
423
|
|
|
* @param string $value The value to format |
|
424
|
|
|
* |
|
425
|
|
|
* @return string|null The formatted date or NULL if the date is not valid |
|
426
|
|
|
*/ |
|
427
|
2 |
|
public function formatDate($value) |
|
428
|
|
|
{ |
|
429
|
|
|
|
|
430
|
|
|
// create a DateTime instance from the passed value |
|
431
|
2 |
|
if ($dateTime = \DateTime::createFromFormat($this->getSourceDateFormat(), $value)) { |
|
432
|
1 |
|
return $dateTime->format('Y-m-d H:i:s'); |
|
433
|
|
|
} |
|
434
|
|
|
|
|
435
|
|
|
// return NULL, if the passed value is NOT a valid date |
|
436
|
1 |
|
return null; |
|
437
|
|
|
} |
|
438
|
|
|
|
|
439
|
|
|
/** |
|
440
|
|
|
* Extracts the elements of the passed value by exploding them |
|
441
|
|
|
* with the also passed delimiter. |
|
442
|
|
|
* |
|
443
|
|
|
* @param string $value The value to extract |
|
444
|
|
|
* @param string|null $delimiter The delimiter used to extrace the elements |
|
445
|
|
|
* |
|
446
|
|
|
* @return array The exploded values |
|
447
|
|
|
*/ |
|
448
|
2 |
|
public function explode($value, $delimiter = null) |
|
449
|
|
|
{ |
|
450
|
|
|
// load the global configuration |
|
451
|
2 |
|
$configuration = $this->getConfiguration(); |
|
452
|
|
|
|
|
453
|
|
|
// initializet delimiter, enclosure and escape char |
|
454
|
2 |
|
$delimiter = $delimiter ? $delimiter : $configuration->getDelimiter(); |
|
455
|
2 |
|
$enclosure = $configuration->getEnclosure(); |
|
456
|
2 |
|
$escape = $configuration->getEscape(); |
|
457
|
|
|
|
|
458
|
|
|
// parse and return the found data as array |
|
459
|
2 |
|
return str_getcsv($value, $delimiter, $enclosure, $escape); |
|
460
|
|
|
} |
|
461
|
|
|
|
|
462
|
|
|
/** |
|
463
|
|
|
* Queries whether or not debug mode is enabled or not, default is TRUE. |
|
464
|
|
|
* |
|
465
|
|
|
* @return boolean TRUE if debug mode is enabled, else FALSE |
|
466
|
|
|
*/ |
|
467
|
1 |
|
public function isDebugMode() |
|
468
|
|
|
{ |
|
469
|
1 |
|
return $this->getConfiguration()->isDebugMode(); |
|
470
|
|
|
} |
|
471
|
|
|
|
|
472
|
|
|
/** |
|
473
|
|
|
* Set's the subject configuration. |
|
474
|
|
|
* |
|
475
|
|
|
* @param \TechDivision\Import\Configuration\SubjectConfigurationInterface $configuration The subject configuration |
|
476
|
|
|
* |
|
477
|
|
|
* @return void |
|
478
|
|
|
*/ |
|
479
|
75 |
|
public function setConfiguration(SubjectConfigurationInterface $configuration) |
|
480
|
|
|
{ |
|
481
|
75 |
|
$this->configuration = $configuration; |
|
482
|
75 |
|
} |
|
483
|
|
|
|
|
484
|
|
|
/** |
|
485
|
|
|
* Return's the subject configuration. |
|
486
|
|
|
* |
|
487
|
|
|
* @return \TechDivision\Import\Configuration\SubjectConfigurationInterface The subject configuration |
|
488
|
|
|
*/ |
|
489
|
75 |
|
public function getConfiguration() |
|
490
|
|
|
{ |
|
491
|
75 |
|
return $this->configuration; |
|
|
|
|
|
|
492
|
|
|
} |
|
493
|
|
|
|
|
494
|
|
|
/** |
|
495
|
|
|
* Return's the logger with the passed name, by default the system logger. |
|
496
|
|
|
* |
|
497
|
|
|
* @param string $name The name of the requested system logger |
|
498
|
|
|
* |
|
499
|
|
|
* @return \Psr\Log\LoggerInterface The logger instance |
|
500
|
|
|
* @throws \Exception Is thrown, if the requested logger is NOT available |
|
501
|
|
|
*/ |
|
502
|
75 |
|
public function getSystemLogger($name = LoggerKeys::SYSTEM) |
|
503
|
|
|
{ |
|
504
|
|
|
|
|
505
|
|
|
// query whether or not, the requested logger is available |
|
506
|
75 |
|
if (isset($this->systemLoggers[$name])) { |
|
507
|
75 |
|
return $this->systemLoggers[$name]; |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
|
// throw an exception if the requested logger is NOT available |
|
511
|
1 |
|
throw new \Exception(sprintf('The requested logger \'%s\' is not available', $name)); |
|
512
|
|
|
} |
|
513
|
|
|
|
|
514
|
|
|
/** |
|
515
|
|
|
* Set's the import adapter instance. |
|
516
|
|
|
* |
|
517
|
|
|
* @param \TechDivision\Import\Adapter\ImportAdapterInterface $importAdapter The import adapter instance |
|
518
|
|
|
* |
|
519
|
|
|
* @return void |
|
520
|
|
|
*/ |
|
521
|
3 |
|
public function setImportAdapter(ImportAdapterInterface $importAdapter) |
|
522
|
|
|
{ |
|
523
|
3 |
|
$this->importAdapter = $importAdapter; |
|
|
|
|
|
|
524
|
3 |
|
} |
|
525
|
|
|
|
|
526
|
|
|
/** |
|
527
|
|
|
* Return's the import adapter instance. |
|
528
|
|
|
* |
|
529
|
|
|
* @return \TechDivision\Import\Adapter\ImportAdapterInterface The import adapter instance |
|
530
|
|
|
*/ |
|
531
|
3 |
|
public function getImportAdapter() |
|
532
|
|
|
{ |
|
533
|
3 |
|
return $this->importAdapter; |
|
|
|
|
|
|
534
|
|
|
} |
|
535
|
|
|
|
|
536
|
|
|
/** |
|
537
|
|
|
* Return's the array with the system logger instances. |
|
538
|
|
|
* |
|
539
|
|
|
* @return array The logger instance |
|
540
|
|
|
*/ |
|
541
|
1 |
|
public function getSystemLoggers() |
|
542
|
|
|
{ |
|
543
|
1 |
|
return $this->systemLoggers; |
|
544
|
|
|
} |
|
545
|
|
|
|
|
546
|
|
|
/** |
|
547
|
|
|
* Return's the RegistryProcessor instance to handle the running threads. |
|
548
|
|
|
* |
|
549
|
|
|
* @return \TechDivision\Import\Services\RegistryProcessorInterface The registry processor instance |
|
550
|
|
|
*/ |
|
551
|
75 |
|
public function getRegistryProcessor() |
|
552
|
|
|
{ |
|
553
|
75 |
|
return $this->registryProcessor; |
|
554
|
|
|
} |
|
555
|
|
|
|
|
556
|
|
|
/** |
|
557
|
|
|
* Set's the unique serial for this import process. |
|
558
|
|
|
* |
|
559
|
|
|
* @param string $serial The unique serial |
|
560
|
|
|
* |
|
561
|
|
|
* @return void |
|
562
|
|
|
*/ |
|
563
|
6 |
|
public function setSerial($serial) |
|
564
|
|
|
{ |
|
565
|
6 |
|
$this->serial = $serial; |
|
566
|
6 |
|
} |
|
567
|
|
|
|
|
568
|
|
|
/** |
|
569
|
|
|
* Return's the unique serial for this import process. |
|
570
|
|
|
* |
|
571
|
|
|
* @return string The unique serial |
|
572
|
|
|
*/ |
|
573
|
3 |
|
public function getSerial() |
|
574
|
|
|
{ |
|
575
|
3 |
|
return $this->serial; |
|
576
|
|
|
} |
|
577
|
|
|
|
|
578
|
|
|
/** |
|
579
|
|
|
* Set's the name of the file to import |
|
580
|
|
|
* |
|
581
|
|
|
* @param string $filename The filename |
|
582
|
|
|
* |
|
583
|
|
|
* @return void |
|
584
|
|
|
*/ |
|
585
|
10 |
|
public function setFilename($filename) |
|
586
|
|
|
{ |
|
587
|
10 |
|
$this->filename = $filename; |
|
588
|
10 |
|
} |
|
589
|
|
|
|
|
590
|
|
|
/** |
|
591
|
|
|
* Return's the name of the file to import. |
|
592
|
|
|
* |
|
593
|
|
|
* @return string The filename |
|
594
|
|
|
*/ |
|
595
|
8 |
|
public function getFilename() |
|
596
|
|
|
{ |
|
597
|
8 |
|
return $this->filename; |
|
598
|
|
|
} |
|
599
|
|
|
|
|
600
|
|
|
/** |
|
601
|
|
|
* Return's the source date format to use. |
|
602
|
|
|
* |
|
603
|
|
|
* @return string The source date format |
|
604
|
|
|
*/ |
|
605
|
4 |
|
public function getSourceDateFormat() |
|
606
|
|
|
{ |
|
607
|
4 |
|
return $this->getConfiguration()->getSourceDateFormat(); |
|
608
|
|
|
} |
|
609
|
|
|
|
|
610
|
|
|
/** |
|
611
|
|
|
* Return's the multiple field delimiter character to use, default value is comma (,). |
|
612
|
|
|
* |
|
613
|
|
|
* @return string The multiple field delimiter character |
|
614
|
|
|
*/ |
|
615
|
1 |
|
public function getMultipleFieldDelimiter() |
|
616
|
|
|
{ |
|
617
|
1 |
|
return $this->getConfiguration()->getMultipleFieldDelimiter(); |
|
618
|
|
|
} |
|
619
|
|
|
|
|
620
|
|
|
/** |
|
621
|
|
|
* Return's the multiple value delimiter character to use, default value is comma (|). |
|
622
|
|
|
* |
|
623
|
|
|
* @return string The multiple value delimiter character |
|
624
|
|
|
*/ |
|
625
|
1 |
|
public function getMultipleValueDelimiter() |
|
626
|
|
|
{ |
|
627
|
1 |
|
return $this->getConfiguration()->getMultipleValueDelimiter(); |
|
628
|
|
|
} |
|
629
|
|
|
|
|
630
|
|
|
/** |
|
631
|
|
|
* Intializes the previously loaded global data for exactly one bunch. |
|
632
|
|
|
* |
|
633
|
|
|
* @param string $serial The serial of the actual import |
|
634
|
|
|
* |
|
635
|
|
|
* @return void |
|
636
|
|
|
* @see \Importer\Csv\Actions\ProductImportAction::prepare() |
|
637
|
|
|
*/ |
|
638
|
75 |
|
public function setUp($serial) |
|
639
|
|
|
{ |
|
640
|
|
|
|
|
641
|
|
|
// load the status of the actual import |
|
642
|
75 |
|
$status = $this->getRegistryProcessor()->getAttribute($serial); |
|
643
|
|
|
|
|
644
|
|
|
// load the global data we've prepared initially |
|
645
|
75 |
|
$this->stores = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::STORES]; |
|
646
|
75 |
|
$this->defaultStore = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::DEFAULT_STORE]; |
|
647
|
75 |
|
$this->storeWebsites = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::STORE_WEBSITES]; |
|
648
|
75 |
|
$this->rootCategories = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::ROOT_CATEGORIES]; |
|
649
|
75 |
|
$this->coreConfigData = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::CORE_CONFIG_DATA]; |
|
650
|
|
|
|
|
651
|
|
|
// initialize the operation name |
|
652
|
75 |
|
$this->operationName = $this->getConfiguration()->getConfiguration()->getOperationName(); |
|
653
|
|
|
|
|
654
|
|
|
// merge the callback mappings with the mappings from the child instance |
|
655
|
75 |
|
$this->callbackMappings = array_merge($this->callbackMappings, $this->getDefaultCallbackMappings()); |
|
656
|
|
|
|
|
657
|
|
|
// merge the callback mappings the the one from the configuration file |
|
658
|
75 |
|
foreach ($this->getConfiguration()->getCallbacks() as $callbackMappings) { |
|
659
|
75 |
|
foreach ($callbackMappings as $attributeCode => $mappings) { |
|
660
|
|
|
// write a log message, that default callback configuration will |
|
661
|
|
|
// be overwritten with the one from the configuration file |
|
662
|
75 |
|
if (isset($this->callbackMappings[$attributeCode])) { |
|
663
|
75 |
|
$this->getSystemLogger()->notice( |
|
664
|
75 |
|
sprintf('Now override callback mappings for attribute %s with values found in configuration file', $attributeCode) |
|
665
|
|
|
); |
|
666
|
|
|
} |
|
667
|
|
|
|
|
668
|
|
|
// override the attributes callbacks |
|
669
|
75 |
|
$this->callbackMappings[$attributeCode] = $mappings; |
|
670
|
|
|
} |
|
671
|
|
|
} |
|
672
|
75 |
|
} |
|
673
|
|
|
|
|
674
|
|
|
/** |
|
675
|
|
|
* Clean up the global data after importing the variants. |
|
676
|
|
|
* |
|
677
|
|
|
* @param string $serial The serial of the actual import |
|
678
|
|
|
* |
|
679
|
|
|
* @return void |
|
680
|
|
|
*/ |
|
681
|
1 |
|
public function tearDown($serial) |
|
682
|
|
|
{ |
|
683
|
|
|
|
|
684
|
|
|
// load the registry processor |
|
685
|
1 |
|
$registryProcessor = $this->getRegistryProcessor(); |
|
686
|
|
|
|
|
687
|
|
|
// update the source directory for the next subject |
|
688
|
1 |
|
$registryProcessor->mergeAttributesRecursive( |
|
689
|
1 |
|
$serial, |
|
690
|
1 |
|
array(RegistryKeys::SOURCE_DIRECTORY => $this->getNewSourceDir($serial)) |
|
691
|
|
|
); |
|
692
|
|
|
|
|
693
|
|
|
// log a debug message with the new source directory |
|
694
|
1 |
|
$this->getSystemLogger()->debug( |
|
695
|
1 |
|
sprintf('Subject %s successfully updated source directory to %s', __CLASS__, $this->getNewSourceDir($serial)) |
|
696
|
|
|
); |
|
697
|
1 |
|
} |
|
698
|
|
|
|
|
699
|
|
|
/** |
|
700
|
|
|
* Return's the next source directory, which will be the target directory |
|
701
|
|
|
* of this subject, in most cases. |
|
702
|
|
|
* |
|
703
|
|
|
* @param string $serial The serial of the actual import |
|
704
|
|
|
* |
|
705
|
|
|
* @return string The new source directory |
|
706
|
|
|
*/ |
|
707
|
1 |
|
protected function getNewSourceDir($serial) |
|
708
|
|
|
{ |
|
709
|
1 |
|
return sprintf('%s/%s', $this->getConfiguration()->getTargetDir(), $serial); |
|
710
|
|
|
} |
|
711
|
|
|
|
|
712
|
|
|
/** |
|
713
|
|
|
* Register the passed observer with the specific type. |
|
714
|
|
|
* |
|
715
|
|
|
* @param \TechDivision\Import\Observers\ObserverInterface $observer The observer to register |
|
716
|
|
|
* @param string $type The type to register the observer with |
|
717
|
|
|
* |
|
718
|
|
|
* @return void |
|
719
|
|
|
*/ |
|
720
|
6 |
|
public function registerObserver(ObserverInterface $observer, $type) |
|
721
|
|
|
{ |
|
722
|
|
|
|
|
723
|
|
|
// query whether or not the array with the callbacks for the |
|
724
|
|
|
// passed type has already been initialized, or not |
|
725
|
6 |
|
if (!isset($this->observers[$type])) { |
|
726
|
6 |
|
$this->observers[$type] = array(); |
|
727
|
|
|
} |
|
728
|
|
|
|
|
729
|
|
|
// append the callback with the instance of the passed type |
|
730
|
6 |
|
$this->observers[$type][] = $observer; |
|
731
|
6 |
|
} |
|
732
|
|
|
|
|
733
|
|
|
/** |
|
734
|
|
|
* Register the passed callback with the specific type. |
|
735
|
|
|
* |
|
736
|
|
|
* @param \TechDivision\Import\Callbacks\CallbackInterface $callback The subject to register the callbacks for |
|
737
|
|
|
* @param string $type The type to register the callback with |
|
738
|
|
|
* |
|
739
|
|
|
* @return void |
|
740
|
|
|
*/ |
|
741
|
2 |
|
public function registerCallback(CallbackInterface $callback, $type) |
|
742
|
|
|
{ |
|
743
|
|
|
|
|
744
|
|
|
// query whether or not the array with the callbacks for the |
|
745
|
|
|
// passed type has already been initialized, or not |
|
746
|
2 |
|
if (!isset($this->callbacks[$type])) { |
|
747
|
2 |
|
$this->callbacks[$type] = array(); |
|
748
|
|
|
} |
|
749
|
|
|
|
|
750
|
|
|
// append the callback with the instance of the passed type |
|
751
|
2 |
|
$this->callbacks[$type][] = $callback; |
|
752
|
2 |
|
} |
|
753
|
|
|
|
|
754
|
|
|
/** |
|
755
|
|
|
* Return's the array with callbacks for the passed type. |
|
756
|
|
|
* |
|
757
|
|
|
* @param string $type The type of the callbacks to return |
|
758
|
|
|
* |
|
759
|
|
|
* @return array The callbacks |
|
760
|
|
|
*/ |
|
761
|
1 |
|
public function getCallbacksByType($type) |
|
762
|
|
|
{ |
|
763
|
|
|
|
|
764
|
|
|
// initialize the array for the callbacks |
|
765
|
1 |
|
$callbacks = array(); |
|
766
|
|
|
|
|
767
|
|
|
// query whether or not callbacks for the type are available |
|
768
|
1 |
|
if (isset($this->callbacks[$type])) { |
|
769
|
1 |
|
$callbacks = $this->callbacks[$type]; |
|
770
|
|
|
} |
|
771
|
|
|
|
|
772
|
|
|
// return the array with the type's callbacks |
|
773
|
1 |
|
return $callbacks; |
|
774
|
|
|
} |
|
775
|
|
|
|
|
776
|
|
|
/** |
|
777
|
|
|
* Return's the array with the available observers. |
|
778
|
|
|
* |
|
779
|
|
|
* @return array The observers |
|
780
|
|
|
*/ |
|
781
|
6 |
|
public function getObservers() |
|
782
|
|
|
{ |
|
783
|
6 |
|
return $this->observers; |
|
784
|
|
|
} |
|
785
|
|
|
|
|
786
|
|
|
/** |
|
787
|
|
|
* Return's the array with the available callbacks. |
|
788
|
|
|
* |
|
789
|
|
|
* @return array The callbacks |
|
790
|
|
|
*/ |
|
791
|
1 |
|
public function getCallbacks() |
|
792
|
|
|
{ |
|
793
|
1 |
|
return $this->callbacks; |
|
794
|
|
|
} |
|
795
|
|
|
|
|
796
|
|
|
/** |
|
797
|
|
|
* Return's the callback mappings for this subject. |
|
798
|
|
|
* |
|
799
|
|
|
* @return array The array with the subject's callback mappings |
|
800
|
|
|
*/ |
|
801
|
2 |
|
public function getCallbackMappings() |
|
802
|
|
|
{ |
|
803
|
2 |
|
return $this->callbackMappings; |
|
804
|
|
|
} |
|
805
|
|
|
|
|
806
|
|
|
/** |
|
807
|
|
|
* Imports the content of the file with the passed filename. |
|
808
|
|
|
* |
|
809
|
|
|
* |
|
810
|
|
|
* @param string $serial The serial of the actual import |
|
811
|
|
|
* @param string $filename The filename to process |
|
812
|
|
|
* |
|
813
|
|
|
* @return void |
|
814
|
|
|
* @throws \Exception Is thrown, if the import can't be processed |
|
815
|
|
|
*/ |
|
816
|
5 |
|
public function import($serial, $filename) |
|
817
|
|
|
{ |
|
818
|
|
|
|
|
819
|
|
|
try { |
|
820
|
|
|
// stop processing, if the filename doesn't match |
|
821
|
5 |
|
if (!$this->match($filename)) { |
|
822
|
1 |
|
return; |
|
823
|
|
|
} |
|
824
|
|
|
|
|
825
|
|
|
// load the system logger instance |
|
826
|
4 |
|
$systemLogger = $this->getSystemLogger(); |
|
827
|
|
|
|
|
828
|
|
|
// prepare the flag filenames |
|
829
|
4 |
|
$inProgressFilename = sprintf('%s.inProgress', $filename); |
|
830
|
4 |
|
$importedFilename = sprintf('%s.imported', $filename); |
|
831
|
4 |
|
$failedFilename = sprintf('%s.failed', $filename); |
|
832
|
|
|
|
|
833
|
|
|
// query whether or not the file has already been imported |
|
834
|
4 |
|
if ($this->isFile($failedFilename) || |
|
835
|
3 |
|
$this->isFile($importedFilename) || |
|
836
|
4 |
|
$this->isFile($inProgressFilename) |
|
837
|
|
|
) { |
|
838
|
|
|
// log a debug message and exit |
|
839
|
1 |
|
$systemLogger->debug(sprintf('Import running, found inProgress file %s', $inProgressFilename)); |
|
840
|
1 |
|
return; |
|
841
|
|
|
} |
|
842
|
|
|
|
|
843
|
|
|
// flag file as in progress |
|
844
|
3 |
|
$this->touch($inProgressFilename); |
|
845
|
|
|
|
|
846
|
|
|
// track the start time |
|
847
|
3 |
|
$startTime = microtime(true); |
|
848
|
|
|
|
|
849
|
|
|
// initialize the serial/filename |
|
850
|
3 |
|
$this->setSerial($serial); |
|
851
|
3 |
|
$this->setFilename($filename); |
|
852
|
|
|
|
|
853
|
|
|
// log a message that the file has to be imported |
|
854
|
3 |
|
$systemLogger->debug(sprintf('Now start importing file %s', $filename)); |
|
855
|
|
|
|
|
856
|
|
|
// let the adapter process the file |
|
857
|
3 |
|
$this->getImportAdapter()->import(array($this, 'importRow'), $filename); |
|
858
|
|
|
|
|
859
|
|
|
// track the time needed for the import in seconds |
|
860
|
1 |
|
$endTime = microtime(true) - $startTime; |
|
861
|
|
|
|
|
862
|
|
|
// log a message that the file has successfully been imported |
|
863
|
1 |
|
$systemLogger->debug(sprintf('Successfully imported file %s in %f s', $filename, $endTime)); |
|
864
|
|
|
|
|
865
|
|
|
// rename flag file, because import has been successfull |
|
866
|
1 |
|
$this->rename($inProgressFilename, $importedFilename); |
|
867
|
|
|
|
|
|
|
|
|
|
868
|
2 |
|
} catch (\Exception $e) { |
|
869
|
|
|
// rename the flag file, because import failed and write the stack trace |
|
870
|
2 |
|
$this->rename($inProgressFilename, $failedFilename); |
|
|
|
|
|
|
871
|
2 |
|
$this->write($failedFilename, $e->__toString()); |
|
872
|
|
|
|
|
873
|
|
|
// do not wrap the exception if not already done |
|
874
|
2 |
|
if ($e instanceof WrappedColumnException) { |
|
875
|
1 |
|
throw $e; |
|
876
|
|
|
} |
|
877
|
|
|
|
|
878
|
|
|
// else wrap and throw the exception |
|
879
|
1 |
|
throw $this->wrapException(array(), $e); |
|
880
|
|
|
} |
|
881
|
1 |
|
} |
|
882
|
|
|
|
|
883
|
|
|
/** |
|
884
|
|
|
* This method queries whether or not the passed filename matches |
|
885
|
|
|
* the pattern, based on the subjects configured prefix. |
|
886
|
|
|
* |
|
887
|
|
|
* @param string $filename The filename to match |
|
888
|
|
|
* |
|
889
|
|
|
* @return boolean TRUE if the filename matches, else FALSE |
|
890
|
|
|
*/ |
|
891
|
5 |
|
protected function match($filename) |
|
892
|
|
|
{ |
|
893
|
|
|
|
|
894
|
|
|
// prepare the pattern to query whether the file has to be processed or not |
|
895
|
5 |
|
$pattern = sprintf( |
|
896
|
5 |
|
'/^.*\/%s.*\\.%s$/', |
|
897
|
5 |
|
$this->getConfiguration()->getPrefix(), |
|
898
|
5 |
|
$this->getConfiguration()->getSuffix() |
|
899
|
|
|
); |
|
900
|
|
|
|
|
901
|
|
|
// stop processing, if the filename doesn't match |
|
902
|
5 |
|
return (boolean) preg_match($pattern, $filename); |
|
903
|
|
|
} |
|
904
|
|
|
|
|
905
|
|
|
/** |
|
906
|
|
|
* Imports the passed row into the database. If the import failed, the exception |
|
907
|
|
|
* will be catched and logged, but the import process will be continued. |
|
908
|
|
|
* |
|
909
|
|
|
* @param array $row The row with the data to be imported |
|
910
|
|
|
* |
|
911
|
|
|
* @return void |
|
912
|
|
|
*/ |
|
913
|
7 |
|
public function importRow(array $row) |
|
914
|
|
|
{ |
|
915
|
|
|
|
|
916
|
|
|
// initialize the row |
|
917
|
7 |
|
$this->row = $row; |
|
918
|
|
|
|
|
919
|
|
|
// raise the line number and reset the skip row flag |
|
920
|
7 |
|
$this->lineNumber++; |
|
921
|
7 |
|
$this->skipRow = false; |
|
922
|
|
|
|
|
923
|
|
|
// initialize the headers with the columns from the first line |
|
924
|
7 |
|
if (sizeof($this->headers) === 0) { |
|
925
|
1 |
|
foreach ($this->row as $value => $key) { |
|
926
|
1 |
|
$this->headers[$this->mapAttributeCodeByHeaderMapping($key)] = $value; |
|
927
|
|
|
} |
|
928
|
1 |
|
return; |
|
929
|
|
|
} |
|
930
|
|
|
|
|
931
|
|
|
// process the observers |
|
932
|
6 |
|
foreach ($this->getObservers() as $observers) { |
|
933
|
|
|
// invoke the pre-import/import and post-import observers |
|
934
|
6 |
|
foreach ($observers as $observer) { |
|
935
|
|
|
// query whether or not we have to skip the row |
|
936
|
6 |
|
if ($this->skipRow) { |
|
937
|
1 |
|
break; |
|
938
|
|
|
} |
|
939
|
|
|
|
|
940
|
|
|
// if not, set the subject and process the observer |
|
941
|
6 |
|
if ($observer instanceof ObserverInterface) { |
|
942
|
6 |
|
$this->row = $observer->handle($this); |
|
943
|
|
|
} |
|
944
|
|
|
} |
|
945
|
|
|
} |
|
946
|
|
|
|
|
947
|
|
|
// log a debug message with the actual line nr/file information |
|
948
|
6 |
|
$this->getSystemLogger()->debug( |
|
949
|
6 |
|
sprintf( |
|
950
|
6 |
|
'Successfully processed row (operation: %s) in file %s on line %d', |
|
951
|
6 |
|
$this->operationName, |
|
952
|
6 |
|
$this->filename, |
|
953
|
6 |
|
$this->lineNumber |
|
954
|
|
|
) |
|
955
|
|
|
); |
|
956
|
6 |
|
} |
|
957
|
|
|
|
|
958
|
|
|
/** |
|
959
|
|
|
* Map the passed attribute code, if a header mapping exists and return the |
|
960
|
|
|
* mapped mapping. |
|
961
|
|
|
* |
|
962
|
|
|
* @param string $attributeCode The attribute code to map |
|
963
|
|
|
* |
|
964
|
|
|
* @return string The mapped attribute code, or the original one |
|
965
|
|
|
*/ |
|
966
|
2 |
|
public function mapAttributeCodeByHeaderMapping($attributeCode) |
|
967
|
|
|
{ |
|
968
|
|
|
|
|
969
|
|
|
// load the header mappings |
|
970
|
2 |
|
$headerMappings = $this->getHeaderMappings(); |
|
971
|
|
|
|
|
972
|
|
|
// query weather or not we've a mapping, if yes, map the attribute code |
|
973
|
2 |
|
if (isset($headerMappings[$attributeCode])) { |
|
974
|
1 |
|
$attributeCode = $headerMappings[$attributeCode]; |
|
975
|
|
|
} |
|
976
|
|
|
|
|
977
|
|
|
// return the (mapped) attribute code |
|
978
|
2 |
|
return $attributeCode; |
|
979
|
|
|
} |
|
980
|
|
|
|
|
981
|
|
|
/** |
|
982
|
|
|
* Queries whether or not that the subject needs an OK file to be processed. |
|
983
|
|
|
* |
|
984
|
|
|
* @return boolean TRUE if the subject needs an OK file, else FALSE |
|
985
|
|
|
*/ |
|
986
|
1 |
|
public function isOkFileNeeded() |
|
987
|
|
|
{ |
|
988
|
1 |
|
return $this->getConfiguration()->isOkFileNeeded(); |
|
989
|
|
|
} |
|
990
|
|
|
|
|
991
|
|
|
/** |
|
992
|
|
|
* Return's the default store. |
|
993
|
|
|
* |
|
994
|
|
|
* @return array The default store |
|
995
|
|
|
*/ |
|
996
|
4 |
|
public function getDefaultStore() |
|
997
|
|
|
{ |
|
998
|
4 |
|
return $this->defaultStore; |
|
999
|
|
|
} |
|
1000
|
|
|
|
|
1001
|
|
|
/** |
|
1002
|
|
|
* Set's the store view code the create the product/attributes for. |
|
1003
|
|
|
* |
|
1004
|
|
|
* @param string $storeViewCode The store view code |
|
1005
|
|
|
* |
|
1006
|
|
|
* @return void |
|
1007
|
|
|
*/ |
|
1008
|
4 |
|
public function setStoreViewCode($storeViewCode) |
|
1009
|
|
|
{ |
|
1010
|
4 |
|
$this->storeViewCode = $storeViewCode; |
|
1011
|
4 |
|
} |
|
1012
|
|
|
|
|
1013
|
|
|
/** |
|
1014
|
|
|
* Return's the store view code the create the product/attributes for. |
|
1015
|
|
|
* |
|
1016
|
|
|
* @param string|null $default The default value to return, if the store view code has not been set |
|
1017
|
|
|
* |
|
1018
|
|
|
* @return string The store view code |
|
1019
|
|
|
*/ |
|
1020
|
8 |
|
public function getStoreViewCode($default = null) |
|
1021
|
|
|
{ |
|
1022
|
|
|
|
|
1023
|
|
|
// return the store view code, if available |
|
1024
|
8 |
|
if ($this->storeViewCode != null) { |
|
1025
|
4 |
|
return $this->storeViewCode; |
|
1026
|
|
|
} |
|
1027
|
|
|
|
|
1028
|
|
|
// if NOT and a default code is available |
|
1029
|
4 |
|
if ($default != null) { |
|
|
|
|
|
|
1030
|
|
|
// return the default value |
|
1031
|
3 |
|
return $default; |
|
1032
|
|
|
} |
|
1033
|
1 |
|
} |
|
1034
|
|
|
|
|
1035
|
|
|
/** |
|
1036
|
|
|
* Return's the store ID of the store with the passed store view code |
|
1037
|
|
|
* |
|
1038
|
|
|
* @param string $storeViewCode The store view code to return the store ID for |
|
1039
|
|
|
* |
|
1040
|
|
|
* @return integer The ID of the store with the passed ID |
|
1041
|
|
|
* @throws \Exception Is thrown, if the store with the actual code is not available |
|
1042
|
|
|
*/ |
|
1043
|
4 |
|
public function getStoreId($storeViewCode) |
|
1044
|
|
|
{ |
|
1045
|
|
|
|
|
1046
|
|
|
// query whether or not, the requested store is available |
|
1047
|
4 |
|
if (isset($this->stores[$storeViewCode])) { |
|
1048
|
3 |
|
return (integer) $this->stores[$storeViewCode][MemberNames::STORE_ID]; |
|
1049
|
|
|
} |
|
1050
|
|
|
|
|
1051
|
|
|
// throw an exception, if not |
|
1052
|
1 |
|
throw new \Exception( |
|
1053
|
1 |
|
sprintf( |
|
1054
|
1 |
|
'Found invalid store view code %s in file %s on line %d', |
|
1055
|
1 |
|
$storeViewCode, |
|
1056
|
1 |
|
$this->getFilename(), |
|
1057
|
1 |
|
$this->getLineNumber() |
|
1058
|
|
|
) |
|
1059
|
|
|
); |
|
1060
|
|
|
} |
|
1061
|
|
|
|
|
1062
|
|
|
/** |
|
1063
|
|
|
* Return's the store ID of the actual row, or of the default store |
|
1064
|
|
|
* if no store view code is set in the CSV file. |
|
1065
|
|
|
* |
|
1066
|
|
|
* @param string|null $default The default store view code to use, if no store view code is set in the CSV file |
|
1067
|
|
|
* |
|
1068
|
|
|
* @return integer The ID of the actual store |
|
1069
|
|
|
* @throws \Exception Is thrown, if the store with the actual code is not available |
|
1070
|
|
|
*/ |
|
1071
|
2 |
|
public function getRowStoreId($default = null) |
|
1072
|
|
|
{ |
|
1073
|
|
|
|
|
1074
|
|
|
// initialize the default store view code, if not passed |
|
1075
|
2 |
|
if ($default == null) { |
|
|
|
|
|
|
1076
|
2 |
|
$defaultStore = $this->getDefaultStore(); |
|
1077
|
2 |
|
$default = $defaultStore[MemberNames::CODE]; |
|
1078
|
|
|
} |
|
1079
|
|
|
|
|
1080
|
|
|
// load the store view code the create the product/attributes for |
|
1081
|
2 |
|
return $this->getStoreId($this->getStoreViewCode($default)); |
|
1082
|
|
|
} |
|
1083
|
|
|
|
|
1084
|
|
|
/** |
|
1085
|
|
|
* Prepare's the store view code in the subject. |
|
1086
|
|
|
* |
|
1087
|
|
|
* @return void |
|
1088
|
|
|
*/ |
|
1089
|
2 |
|
public function prepareStoreViewCode() |
|
1090
|
|
|
{ |
|
1091
|
|
|
|
|
1092
|
|
|
// re-set the store view code |
|
1093
|
2 |
|
$this->setStoreViewCode(null); |
|
1094
|
|
|
|
|
1095
|
|
|
// initialize the store view code |
|
1096
|
2 |
|
if ($storeViewCode = $this->getValue(ColumnKeys::STORE_VIEW_CODE)) { |
|
1097
|
2 |
|
$this->setStoreViewCode($storeViewCode); |
|
1098
|
|
|
} |
|
1099
|
2 |
|
} |
|
1100
|
|
|
|
|
1101
|
|
|
/** |
|
1102
|
|
|
* Return's the root category for the actual view store. |
|
1103
|
|
|
* |
|
1104
|
|
|
* @return array The store's root category |
|
1105
|
|
|
* @throws \Exception Is thrown if the root category for the passed store code is NOT available |
|
1106
|
|
|
*/ |
|
1107
|
2 |
|
public function getRootCategory() |
|
1108
|
|
|
{ |
|
1109
|
|
|
|
|
1110
|
|
|
// load the default store |
|
1111
|
2 |
|
$defaultStore = $this->getDefaultStore(); |
|
1112
|
|
|
|
|
1113
|
|
|
// load the actual store view code |
|
1114
|
2 |
|
$storeViewCode = $this->getStoreViewCode($defaultStore[MemberNames::CODE]); |
|
1115
|
|
|
|
|
1116
|
|
|
// query weather or not we've a root category or not |
|
1117
|
2 |
|
if (isset($this->rootCategories[$storeViewCode])) { |
|
1118
|
1 |
|
return $this->rootCategories[$storeViewCode]; |
|
1119
|
|
|
} |
|
1120
|
|
|
|
|
1121
|
|
|
// throw an exception if the root category is NOT available |
|
1122
|
1 |
|
throw new \Exception(sprintf('Root category for %s is not available', $storeViewCode)); |
|
1123
|
|
|
} |
|
1124
|
|
|
|
|
1125
|
|
|
/** |
|
1126
|
|
|
* Return's the Magento configuration value. |
|
1127
|
|
|
* |
|
1128
|
|
|
* @param string $path The Magento path of the requested configuration value |
|
1129
|
|
|
* @param mixed $default The default value that has to be returned, if the requested configuration value is not set |
|
1130
|
|
|
* @param string $scope The scope the configuration value has been set |
|
1131
|
|
|
* @param integer $scopeId The scope ID the configuration value has been set |
|
1132
|
|
|
* |
|
1133
|
|
|
* @return mixed The configuration value |
|
1134
|
|
|
* @throws \Exception Is thrown, if nor a value can be found or a default value has been passed |
|
1135
|
|
|
*/ |
|
1136
|
5 |
|
public function getCoreConfigData($path, $default = null, $scope = ScopeKeys::SCOPE_DEFAULT, $scopeId = 0) |
|
1137
|
|
|
{ |
|
1138
|
|
|
|
|
1139
|
|
|
// initialize the core config data |
|
1140
|
|
|
$coreConfigData = array( |
|
1141
|
5 |
|
MemberNames::PATH => $path, |
|
1142
|
5 |
|
MemberNames::SCOPE => $scope, |
|
1143
|
5 |
|
MemberNames::SCOPE_ID => $scopeId |
|
1144
|
|
|
); |
|
1145
|
|
|
|
|
1146
|
|
|
// generate the UID from the passed data |
|
1147
|
5 |
|
$uniqueIdentifier = $this->coreConfigDataUidGenerator->generate($coreConfigData); |
|
1148
|
|
|
|
|
1149
|
|
|
// iterate over the core config data and try to find the requested configuration value |
|
1150
|
5 |
|
if (isset($this->coreConfigData[$uniqueIdentifier])) { |
|
1151
|
1 |
|
return $this->coreConfigData[$uniqueIdentifier][MemberNames::VALUE]; |
|
1152
|
|
|
} |
|
1153
|
|
|
|
|
1154
|
|
|
// query whether or not we've to query for the configuration value on fallback level 'websites' also |
|
1155
|
4 |
|
if ($scope === ScopeKeys::SCOPE_STORES) { |
|
1156
|
|
|
// query whether or not the website with the passed ID is available |
|
1157
|
2 |
|
foreach ($this->storeWebsites as $storeWebsite) { |
|
1158
|
2 |
|
if ($storeWebsite[MemberNames::WEBSITE_ID] === $scopeId) { |
|
1159
|
|
|
// replace scope with 'websites' and website ID |
|
1160
|
2 |
|
$coreConfigData = array_merge( |
|
1161
|
2 |
|
$coreConfigData, |
|
1162
|
|
|
array( |
|
1163
|
2 |
|
MemberNames::SCOPE => ScopeKeys::SCOPE_WEBSITES, |
|
1164
|
2 |
|
MemberNames::SCOPE_ID => $storeWebsite[MemberNames::WEBSITE_ID] |
|
1165
|
|
|
) |
|
1166
|
|
|
); |
|
1167
|
|
|
|
|
1168
|
|
|
// generate the UID from the passed data, merged with the 'websites' scope and ID |
|
1169
|
2 |
|
$uniqueIdentifier = $this->coreConfigDataUidGenerator->generate($coreConfigData); |
|
1170
|
|
|
|
|
1171
|
|
|
// query whether or not, the configuration value on 'websites' level |
|
1172
|
2 |
View Code Duplication |
if (isset($this->coreConfigData[$uniqueIdentifier][MemberNames::VALUE])) { |
|
|
|
|
|
|
1173
|
2 |
|
return $this->coreConfigData[$uniqueIdentifier][MemberNames::VALUE]; |
|
1174
|
|
|
} |
|
1175
|
|
|
} |
|
1176
|
|
|
} |
|
1177
|
|
|
} |
|
1178
|
|
|
|
|
1179
|
|
|
// replace scope with 'default' and scope ID '0' |
|
1180
|
3 |
|
$coreConfigData = array_merge( |
|
1181
|
3 |
|
$coreConfigData, |
|
1182
|
|
|
array( |
|
1183
|
3 |
|
MemberNames::SCOPE => ScopeKeys::SCOPE_DEFAULT, |
|
1184
|
3 |
|
MemberNames::SCOPE_ID => 0 |
|
1185
|
|
|
) |
|
1186
|
|
|
); |
|
1187
|
|
|
|
|
1188
|
|
|
// generate the UID from the passed data, merged with the 'default' scope and ID 0 |
|
1189
|
3 |
|
$uniqueIdentifier = $this->coreConfigDataUidGenerator->generate($coreConfigData); |
|
1190
|
|
|
|
|
1191
|
|
|
// query whether or not, the configuration value on 'default' level |
|
1192
|
3 |
View Code Duplication |
if (isset($this->coreConfigData[$uniqueIdentifier][MemberNames::VALUE])) { |
|
|
|
|
|
|
1193
|
1 |
|
return $this->coreConfigData[$uniqueIdentifier][MemberNames::VALUE]; |
|
1194
|
|
|
} |
|
1195
|
|
|
|
|
1196
|
|
|
// if not, return the passed default value |
|
1197
|
2 |
|
if ($default !== null) { |
|
1198
|
1 |
|
return $default; |
|
1199
|
|
|
} |
|
1200
|
|
|
|
|
1201
|
|
|
// throw an exception if no value can be found |
|
1202
|
|
|
// in the Magento configuration |
|
1203
|
1 |
|
throw new \Exception( |
|
1204
|
1 |
|
sprintf( |
|
1205
|
1 |
|
'Can\'t find a value for configuration "%s-%s-%d" in "core_config_data"', |
|
1206
|
1 |
|
$path, |
|
1207
|
1 |
|
$scope, |
|
1208
|
1 |
|
$scopeId |
|
1209
|
|
|
) |
|
1210
|
|
|
); |
|
1211
|
|
|
} |
|
1212
|
|
|
|
|
1213
|
|
|
/** |
|
1214
|
|
|
* Resolve the original column name for the passed one. |
|
1215
|
|
|
* |
|
1216
|
|
|
* @param string $columnName The column name that has to be resolved |
|
1217
|
|
|
* |
|
1218
|
|
|
* @return string|null The original column name |
|
1219
|
|
|
*/ |
|
1220
|
2 |
|
public function resolveOriginalColumnName($columnName) |
|
1221
|
|
|
{ |
|
1222
|
|
|
|
|
1223
|
|
|
// try to load the original data |
|
1224
|
2 |
|
$originalData = $this->getOriginalData(); |
|
1225
|
|
|
|
|
1226
|
|
|
// query whether or not original data is available |
|
1227
|
2 |
|
if (isset($originalData[ColumnKeys::ORIGINAL_COLUMN_NAMES])) { |
|
1228
|
|
|
// query whether or not the original column name is available |
|
1229
|
1 |
|
if (isset($originalData[ColumnKeys::ORIGINAL_COLUMN_NAMES][$columnName])) { |
|
1230
|
1 |
|
return $originalData[ColumnKeys::ORIGINAL_COLUMN_NAMES][$columnName]; |
|
1231
|
|
|
} |
|
1232
|
|
|
|
|
1233
|
|
|
// query whether or a wildcard column name is available |
|
1234
|
1 |
|
if (isset($originalData[ColumnKeys::ORIGINAL_COLUMN_NAMES]['*'])) { |
|
1235
|
1 |
|
return $originalData[ColumnKeys::ORIGINAL_COLUMN_NAMES]['*']; |
|
1236
|
|
|
} |
|
1237
|
|
|
} |
|
1238
|
|
|
|
|
1239
|
|
|
// return the original column name |
|
1240
|
1 |
|
return $columnName; |
|
1241
|
|
|
} |
|
1242
|
|
|
|
|
1243
|
|
|
/** |
|
1244
|
|
|
* Return's the original data if available, or an empty array. |
|
1245
|
|
|
* |
|
1246
|
|
|
* @return array The original data |
|
1247
|
|
|
*/ |
|
1248
|
2 |
|
public function getOriginalData() |
|
1249
|
|
|
{ |
|
1250
|
|
|
|
|
1251
|
|
|
// initialize the array for the original data |
|
1252
|
2 |
|
$originalData = array(); |
|
1253
|
|
|
|
|
1254
|
|
|
// query whether or not the column contains original data |
|
1255
|
2 |
|
if ($this->hasOriginalData()) { |
|
1256
|
|
|
// unerialize the original data from the column |
|
1257
|
1 |
|
$originalData = unserialize($this->row[$this->headers[ColumnKeys::ORIGINAL_DATA]]); |
|
1258
|
|
|
} |
|
1259
|
|
|
|
|
1260
|
|
|
// return an empty array, if not |
|
1261
|
2 |
|
return $originalData; |
|
1262
|
|
|
} |
|
1263
|
|
|
|
|
1264
|
|
|
/** |
|
1265
|
|
|
* Query's whether or not the actual column contains original data like |
|
1266
|
|
|
* filename, line number and column names. |
|
1267
|
|
|
* |
|
1268
|
|
|
* @return boolean TRUE if the actual column contains origin data, else FALSE |
|
1269
|
|
|
*/ |
|
1270
|
3 |
|
public function hasOriginalData() |
|
1271
|
|
|
{ |
|
1272
|
3 |
|
return isset($this->headers[ColumnKeys::ORIGINAL_DATA]) && isset($this->row[$this->headers[ColumnKeys::ORIGINAL_DATA]]); |
|
1273
|
|
|
} |
|
1274
|
|
|
|
|
1275
|
|
|
/** |
|
1276
|
|
|
* Wraps the passed exeception into a new one by trying to resolve the original filname, |
|
1277
|
|
|
* line number and column names and use it for a detailed exception message. |
|
1278
|
|
|
* |
|
1279
|
|
|
* @param array $columnNames The column names that should be resolved and wrapped |
|
1280
|
|
|
* @param \Exception $parent The exception we want to wrap |
|
1281
|
|
|
* @param string $className The class name of the exception type we want to wrap the parent one |
|
1282
|
|
|
* |
|
1283
|
|
|
* @return \Exception the wrapped exception |
|
1284
|
|
|
*/ |
|
1285
|
2 |
|
public function wrapException( |
|
1286
|
|
|
array $columnNames = array(), |
|
1287
|
|
|
\Exception $parent = null, |
|
1288
|
|
|
$className = '\TechDivision\Import\Exceptions\WrappedColumnException' |
|
1289
|
|
|
) { |
|
1290
|
|
|
|
|
1291
|
|
|
// initialize the message |
|
1292
|
2 |
|
$message = $parent->getMessage(); |
|
|
|
|
|
|
1293
|
|
|
|
|
1294
|
|
|
// query whether or not has been a result of invalid data of a previous column of a CSV file |
|
1295
|
2 |
|
if ($this->hasOriginalData()) { |
|
1296
|
|
|
// load the original data |
|
1297
|
1 |
|
$originalData = $this->getOriginalData(); |
|
1298
|
|
|
|
|
1299
|
|
|
// replace old filename and line number of the original message |
|
1300
|
1 |
|
$message = $this->appendExceptionSuffix( |
|
1301
|
1 |
|
$this->stripExceptionSuffix($message), |
|
1302
|
1 |
|
$originalData[ColumnKeys::ORIGINAL_FILENAME], |
|
1303
|
1 |
|
$originalData[ColumnKeys::ORIGINAL_LINE_NUMBER] |
|
1304
|
|
|
); |
|
1305
|
|
|
|
|
|
|
|
|
|
1306
|
|
|
} else { |
|
1307
|
|
|
// append filename and line number to the original message |
|
1308
|
1 |
|
$message = $this->appendExceptionSuffix( |
|
1309
|
1 |
|
$this->stripExceptionSuffix($message), |
|
1310
|
1 |
|
$this->filename, |
|
1311
|
1 |
|
$this->lineNumber |
|
1312
|
|
|
); |
|
1313
|
|
|
} |
|
1314
|
|
|
|
|
1315
|
|
|
// query whether or not, column names has been passed |
|
1316
|
2 |
|
if (sizeof($columnNames) > 0) { |
|
1317
|
|
|
// prepare the original column names |
|
1318
|
1 |
|
$originalColumnNames = array(); |
|
1319
|
1 |
|
foreach ($columnNames as $columnName) { |
|
1320
|
1 |
|
$originalColumnNames[] = $this->resolveOriginalColumnName($columnName); |
|
1321
|
|
|
} |
|
1322
|
|
|
|
|
1323
|
|
|
// append the column information |
|
1324
|
1 |
|
$message = sprintf('%s in column(s) %s', $message, implode(', ', $originalColumnNames)); |
|
1325
|
|
|
} |
|
1326
|
|
|
|
|
1327
|
|
|
// create a new exception and wrap the parent one |
|
1328
|
2 |
|
return new $className($message, null, $parent); |
|
1329
|
|
|
} |
|
1330
|
|
|
|
|
1331
|
|
|
/** |
|
1332
|
|
|
* Strip's the exception suffix containing filename and line number from the |
|
1333
|
|
|
* passed message. |
|
1334
|
|
|
* |
|
1335
|
|
|
* @param string $message The message to strip the exception suffix from |
|
1336
|
|
|
* |
|
1337
|
|
|
* @return mixed The message without the exception suffix |
|
1338
|
|
|
*/ |
|
1339
|
2 |
|
public function stripExceptionSuffix($message) |
|
1340
|
|
|
{ |
|
1341
|
2 |
|
return str_replace($this->appendExceptionSuffix(), '', $message); |
|
1342
|
|
|
} |
|
1343
|
|
|
|
|
1344
|
|
|
/** |
|
1345
|
|
|
* Append's the exception suffix containing filename and line number to the |
|
1346
|
|
|
* passed message. If no message has been passed, only the suffix will be |
|
1347
|
|
|
* returned |
|
1348
|
|
|
* |
|
1349
|
|
|
* @param string|null $message The message to append the exception suffix to |
|
1350
|
|
|
* @param string|null $filename The filename used to create the suffix |
|
1351
|
|
|
* @param string|null $lineNumber The line number used to create the suffx |
|
1352
|
|
|
* |
|
1353
|
|
|
* @return string The message with the appended exception suffix |
|
1354
|
|
|
*/ |
|
1355
|
7 |
|
public function appendExceptionSuffix($message = null, $filename = null, $lineNumber = null) |
|
1356
|
|
|
{ |
|
1357
|
|
|
|
|
1358
|
|
|
// query whether or not a filename has been passed |
|
1359
|
7 |
|
if ($filename === null) { |
|
1360
|
7 |
|
$filename = $this->getFilename(); |
|
1361
|
|
|
} |
|
1362
|
|
|
|
|
1363
|
|
|
// query whether or not a line number has been passed |
|
1364
|
7 |
|
if ($lineNumber === null) { |
|
1365
|
7 |
|
$lineNumber = $this->getLineNumber(); |
|
1366
|
|
|
} |
|
1367
|
|
|
|
|
1368
|
|
|
// if no message has been passed, only return the suffix |
|
1369
|
7 |
|
if ($message === null) { |
|
1370
|
2 |
|
return sprintf(' in file %s on line %d', $filename, $lineNumber); |
|
1371
|
|
|
} |
|
1372
|
|
|
|
|
1373
|
|
|
// concatenate the message with the suffix and return it |
|
1374
|
7 |
|
return sprintf('%s in file %s on line %d', $message, $filename, $lineNumber); |
|
1375
|
|
|
} |
|
1376
|
|
|
|
|
1377
|
|
|
/** |
|
1378
|
|
|
* Raises the value for the counter with the passed key by one. |
|
1379
|
|
|
* |
|
1380
|
|
|
* @param mixed $counterName The name of the counter to raise |
|
1381
|
|
|
* |
|
1382
|
|
|
* @return integer The counter's new value |
|
1383
|
|
|
*/ |
|
1384
|
1 |
|
public function raiseCounter($counterName) |
|
1385
|
|
|
{ |
|
1386
|
|
|
|
|
1387
|
|
|
// raise the counter with the passed name |
|
1388
|
1 |
|
return $this->getRegistryProcessor()->raiseCounter( |
|
1389
|
1 |
|
$this->getSerial(), |
|
1390
|
1 |
|
$counterName |
|
1391
|
|
|
); |
|
1392
|
|
|
} |
|
1393
|
|
|
|
|
1394
|
|
|
/** |
|
1395
|
|
|
* Merge the passed array into the status of the actual import. |
|
1396
|
|
|
* |
|
1397
|
|
|
* @param array $status The status information to be merged |
|
1398
|
|
|
* |
|
1399
|
|
|
* @return void |
|
1400
|
|
|
*/ |
|
1401
|
1 |
|
public function mergeAttributesRecursive(array $status) |
|
1402
|
|
|
{ |
|
1403
|
|
|
|
|
1404
|
|
|
// merge the passed status |
|
1405
|
1 |
|
$this->getRegistryProcessor()->mergeAttributesRecursive( |
|
1406
|
1 |
|
$this->getSerial(), |
|
1407
|
1 |
|
$status |
|
1408
|
|
|
); |
|
1409
|
1 |
|
} |
|
1410
|
|
|
} |
|
1411
|
|
|
|
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.