1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* TechDivision\Import\Product\Subjects\BunchSubject |
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-product |
18
|
|
|
* @link http://www.techdivision.com |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace TechDivision\Import\Product\Subjects; |
22
|
|
|
|
23
|
|
|
use Doctrine\Common\Collections\Collection; |
24
|
|
|
use League\Event\EmitterInterface; |
25
|
|
|
use TechDivision\Import\Loaders\LoaderInterface; |
26
|
|
|
use TechDivision\Import\Services\RegistryProcessorInterface; |
27
|
|
|
use TechDivision\Import\Utils\Generators\GeneratorInterface; |
28
|
|
|
use TechDivision\Import\Utils\StoreViewCodes; |
29
|
|
|
use TechDivision\Import\Utils\Mappings\MapperInterface; |
30
|
|
|
use TechDivision\Import\Product\Utils\MemberNames; |
31
|
|
|
use TechDivision\Import\Product\Utils\RegistryKeys; |
32
|
|
|
use TechDivision\Import\Product\Utils\VisibilityKeys; |
33
|
|
|
use TechDivision\Import\Product\Utils\ConfigurationKeys; |
34
|
|
|
use TechDivision\Import\Subjects\ExportableTrait; |
35
|
|
|
use TechDivision\Import\Subjects\FileUploadTrait; |
36
|
|
|
use TechDivision\Import\Subjects\ExportableSubjectInterface; |
37
|
|
|
use TechDivision\Import\Subjects\FileUploadSubjectInterface; |
38
|
|
|
use TechDivision\Import\Subjects\UrlKeyAwareSubjectInterface; |
39
|
|
|
use TechDivision\Import\Subjects\CleanUpColumnsSubjectInterface; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* The subject implementation that handles the business logic to persist products. |
43
|
|
|
* |
44
|
|
|
* @author Tim Wagner <[email protected]> |
45
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
46
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
47
|
|
|
* @link https://github.com/techdivision/import-product |
48
|
|
|
* @link http://www.techdivision.com |
49
|
|
|
*/ |
50
|
|
|
class BunchSubject extends AbstractProductSubject implements ExportableSubjectInterface, FileUploadSubjectInterface, UrlKeyAwareSubjectInterface, CleanUpColumnsSubjectInterface |
51
|
|
|
{ |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* The trait that implements the export functionality. |
55
|
|
|
* |
56
|
|
|
* @var \TechDivision\Import\Subjects\ExportableTrait |
57
|
|
|
*/ |
58
|
|
|
use ExportableTrait; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* The trait that provides file upload functionality. |
62
|
|
|
* |
63
|
|
|
* @var \TechDivision\Import\Subjects\FileUploadTrait |
64
|
|
|
*/ |
65
|
|
|
use FileUploadTrait; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* The array with the pre-loaded entity IDs. |
69
|
|
|
* |
70
|
|
|
* @var array |
71
|
|
|
*/ |
72
|
|
|
protected $preLoadedEntityIds = array(); |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Mappings for the table column => CSV column header. |
76
|
|
|
* |
77
|
|
|
* @var array |
78
|
|
|
*/ |
79
|
|
|
protected $headerStockMappings = array( |
80
|
|
|
'qty' => array('qty', 'float'), |
81
|
|
|
'min_qty' => array('out_of_stock_qty', 'float'), |
82
|
|
|
'use_config_min_qty' => array('use_config_min_qty', 'int'), |
83
|
|
|
'is_qty_decimal' => array('is_qty_decimal', 'int'), |
84
|
|
|
'backorders' => array('allow_backorders', 'int'), |
85
|
|
|
'use_config_backorders' => array('use_config_backorders', 'int'), |
86
|
|
|
'min_sale_qty' => array('min_cart_qty', 'float'), |
87
|
|
|
'use_config_min_sale_qty' => array('use_config_min_sale_qty', 'int'), |
88
|
|
|
'max_sale_qty' => array('max_cart_qty', 'float'), |
89
|
|
|
'use_config_max_sale_qty' => array('use_config_max_sale_qty', 'int'), |
90
|
|
|
'is_in_stock' => array('is_in_stock', 'int'), |
91
|
|
|
'notify_stock_qty' => array('notify_on_stock_below', 'float'), |
92
|
|
|
'use_config_notify_stock_qty' => array('use_config_notify_stock_qty', 'int'), |
93
|
|
|
'manage_stock' => array('manage_stock', 'int'), |
94
|
|
|
'use_config_manage_stock' => array('use_config_manage_stock', 'int'), |
95
|
|
|
'use_config_qty_increments' => array('use_config_qty_increments', 'int'), |
96
|
|
|
'qty_increments' => array('qty_increments', 'float'), |
97
|
|
|
'use_config_enable_qty_inc' => array('use_config_enable_qty_inc', 'int'), |
98
|
|
|
'enable_qty_increments' => array('enable_qty_increments', 'int'), |
99
|
|
|
'is_decimal_divided' => array('is_decimal_divided', 'int'), |
100
|
|
|
); |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* The array with the available visibility keys. |
104
|
|
|
* |
105
|
|
|
* @var array |
106
|
|
|
*/ |
107
|
|
|
protected $availableVisibilities = array( |
108
|
|
|
'Not Visible Individually' => VisibilityKeys::VISIBILITY_NOT_VISIBLE, |
109
|
|
|
'Catalog' => VisibilityKeys::VISIBILITY_IN_CATALOG, |
110
|
|
|
'Search' => VisibilityKeys::VISIBILITY_IN_SEARCH, |
111
|
|
|
'Catalog, Search' => VisibilityKeys::VISIBILITY_BOTH |
112
|
|
|
); |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* The default callback mappings for the Magento standard product attributes. |
116
|
|
|
* |
117
|
|
|
* @var array |
118
|
|
|
*/ |
119
|
|
|
protected $defaultCallbackMappings = array( |
120
|
|
|
'visibility' => array('import_product.callback.visibility'), |
121
|
|
|
'tax_class_id' => array('import_product.callback.tax.class'), |
122
|
|
|
'bundle_price_type' => array('import_product_bundle.callback.bundle.type'), |
123
|
|
|
'bundle_sku_type' => array('import_product_bundle.callback.bundle.type'), |
124
|
|
|
'bundle_weight_type' => array('import_product_bundle.callback.bundle.type'), |
125
|
|
|
'bundle_price_view' => array('import_product_bundle.callback.bundle.price.view'), |
126
|
|
|
'bundle_shipment_type' => array('import_product_bundle.callback.bundle.shipment.type') |
127
|
|
|
); |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* The available entity types. |
131
|
|
|
* |
132
|
|
|
* @var array |
133
|
|
|
*/ |
134
|
|
|
protected $entityTypes = array(); |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* The media roles loader instance. |
138
|
|
|
* |
139
|
|
|
* @var \TechDivision\Import\Loaders\LoaderInterface |
140
|
|
|
*/ |
141
|
|
|
protected $mediaRolesLoader; |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* The entity type code mapper instance. |
145
|
|
|
* |
146
|
|
|
* @var \TechDivision\Import\Utils\Mappings\MapperInterface |
147
|
|
|
*/ |
148
|
|
|
protected $entityTypeCodeMapper; |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* BunchSubject constructor |
152
|
|
|
* |
153
|
|
|
* @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor The registry processor instance |
154
|
|
|
* @param \TechDivision\Import\Utils\Generators\GeneratorInterface $coreConfigDataUidGenerator The UID generator for the core config data |
155
|
|
|
* @param \Doctrine\Common\Collections\Collection $systemLoggers The array with the system loggers instances |
156
|
|
|
* @param \League\Event\EmitterInterface $emitter The event emitter instance |
157
|
|
|
* @param \TechDivision\Import\Loaders\LoaderInterface $mediaRolesLoader The media type loader instance |
158
|
|
|
* @param \TechDivision\Import\Utils\Mappings\MapperInterface $entityTypeCodeMapper The entity type code mapper instance |
159
|
|
|
*/ |
160
|
18 |
|
public function __construct( |
161
|
|
|
RegistryProcessorInterface $registryProcessor, |
162
|
|
|
GeneratorInterface $coreConfigDataUidGenerator, |
163
|
|
|
Collection $systemLoggers, |
164
|
|
|
EmitterInterface $emitter, |
165
|
|
|
LoaderInterface $mediaRolesLoader, |
166
|
|
|
MapperInterface $entityTypeCodeMapper |
167
|
|
|
) { |
168
|
|
|
|
169
|
|
|
// set the loader for the media roles and the entity type code mapper |
170
|
18 |
|
$this->mediaRolesLoader = $mediaRolesLoader; |
171
|
18 |
|
$this->entityTypeCodeMapper = $entityTypeCodeMapper; |
172
|
|
|
|
173
|
|
|
// pass the other instances to the parent constructor |
174
|
18 |
|
parent::__construct($registryProcessor, $coreConfigDataUidGenerator, $systemLoggers, $emitter); |
175
|
18 |
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Intializes the previously loaded global data for exactly one bunch. |
179
|
|
|
* |
180
|
|
|
* @param string $serial The serial of the actual import |
181
|
|
|
* |
182
|
|
|
* @return void |
183
|
|
|
*/ |
184
|
18 |
|
public function setUp($serial) |
185
|
|
|
{ |
186
|
|
|
|
187
|
|
|
// load the status of the actual import |
188
|
18 |
|
$status = $this->getRegistryProcessor()->getAttribute(RegistryKeys::STATUS); |
189
|
|
|
|
190
|
|
|
// load the global data we've prepared initially |
191
|
18 |
|
$this->entityTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::ENTITY_TYPES]; |
192
|
|
|
|
193
|
|
|
// initialize the flag whether to copy images or not |
194
|
18 |
|
if ($this->getConfiguration()->hasParam(ConfigurationKeys::COPY_IMAGES)) { |
195
|
|
|
$this->setCopyImages($this->getConfiguration()->getParam(ConfigurationKeys::COPY_IMAGES)); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
// initialize the flag whether to override images or not |
199
|
18 |
|
if ($this->getConfiguration()->hasParam(ConfigurationKeys::OVERRIDE_IMAGES)) { |
200
|
|
|
$this->setOverrideImages($this->getConfiguration()->getParam(ConfigurationKeys::OVERRIDE_IMAGES)); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
// initialize media directory => can be absolute or relative |
204
|
18 |
View Code Duplication |
if ($this->getConfiguration()->hasParam(ConfigurationKeys::MEDIA_DIRECTORY)) { |
|
|
|
|
205
|
|
|
try { |
206
|
|
|
$this->setMediaDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::MEDIA_DIRECTORY))); |
207
|
|
|
} catch (\InvalidArgumentException $iae) { |
208
|
|
|
$this->getSystemLogger()->debug($iae->getMessage()); |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
// initialize images directory => can be absolute or relative |
213
|
18 |
View Code Duplication |
if ($this->getConfiguration()->hasParam(ConfigurationKeys::IMAGES_FILE_DIRECTORY)) { |
|
|
|
|
214
|
|
|
try { |
215
|
|
|
$this->setImagesFileDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::IMAGES_FILE_DIRECTORY))); |
216
|
|
|
} catch (\InvalidArgumentException $iae) { |
217
|
|
|
$this->getSystemLogger()->debug($iae->getMessage()); |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
// invoke the parent method |
222
|
18 |
|
parent::setUp($serial); |
223
|
18 |
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Clean up the global data after importing the bunch. |
227
|
|
|
* |
228
|
|
|
* @param string $serial The serial of the actual import |
229
|
|
|
* |
230
|
|
|
* @return void |
231
|
|
|
*/ |
232
|
|
|
public function tearDown($serial) |
233
|
|
|
{ |
234
|
|
|
|
235
|
|
|
// invoke the parent method |
236
|
|
|
parent::tearDown($serial); |
237
|
|
|
|
238
|
|
|
// load the registry processor |
239
|
|
|
$registryProcessor = $this->getRegistryProcessor(); |
240
|
|
|
|
241
|
|
|
// update the status |
242
|
|
|
$registryProcessor->mergeAttributesRecursive( |
243
|
|
|
RegistryKeys::STATUS, |
244
|
|
|
array( |
245
|
|
|
RegistryKeys::PRE_LOADED_ENTITY_IDS => $this->preLoadedEntityIds, |
246
|
|
|
) |
247
|
|
|
); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Return's the default callback mappings. |
252
|
|
|
* |
253
|
|
|
* @return array The default callback mappings |
254
|
|
|
*/ |
255
|
|
|
public function getDefaultCallbackMappings() |
256
|
|
|
{ |
257
|
|
|
return $this->defaultCallbackMappings; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Return's the mappings for the table column => CSV column header. |
262
|
|
|
* |
263
|
|
|
* @return array The header stock mappings |
264
|
|
|
*/ |
265
|
1 |
|
public function getHeaderStockMappings() |
266
|
|
|
{ |
267
|
1 |
|
return $this->headerStockMappings; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* Return's the visibility key for the passed visibility string. |
272
|
|
|
* |
273
|
|
|
* @param string $visibility The visibility string to return the key for |
274
|
|
|
* |
275
|
|
|
* @return integer The requested visibility key |
276
|
|
|
* @throws \Exception Is thrown, if the requested visibility is not available |
277
|
|
|
*/ |
278
|
|
|
public function getVisibilityIdByValue($visibility) |
279
|
|
|
{ |
280
|
|
|
|
281
|
|
|
// query whether or not, the requested visibility is available |
282
|
|
|
if (isset($this->availableVisibilities[$visibility])) { |
283
|
|
|
// load the visibility ID, add the mapping and return the ID |
284
|
|
|
return $this->availableVisibilities[$visibility]; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
// throw an exception, if not |
288
|
|
|
throw new \Exception( |
289
|
|
|
$this->appendExceptionSuffix( |
290
|
|
|
sprintf('Found invalid visibility %s', $visibility) |
291
|
|
|
) |
292
|
|
|
); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Pre-load the entity ID for the passed product. |
297
|
|
|
* |
298
|
|
|
* @param array $product The product to be pre-loaded |
299
|
|
|
* |
300
|
|
|
* @return void |
301
|
|
|
*/ |
302
|
|
|
public function preLoadEntityId(array $product) |
303
|
|
|
{ |
304
|
|
|
$this->preLoadedEntityIds[$product[MemberNames::SKU]] = $product[MemberNames::ENTITY_ID]; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* Return's the entity type for the configured entity type code. |
309
|
|
|
* |
310
|
|
|
* @return array The requested entity type |
311
|
|
|
* @throws \Exception Is thrown, if the requested entity type is not available |
312
|
|
|
*/ |
313
|
1 |
View Code Duplication |
public function getEntityType() |
|
|
|
|
314
|
|
|
{ |
315
|
|
|
|
316
|
|
|
// query whether or not the entity type with the passed code is available |
317
|
1 |
|
if (isset($this->entityTypes[$entityTypeCode = $this->getEntityTypeCode()])) { |
318
|
1 |
|
return $this->entityTypes[$entityTypeCode]; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
// throw a new exception |
322
|
|
|
throw new \Exception( |
323
|
|
|
$this->appendExceptionSuffix( |
324
|
|
|
sprintf('Requested entity type "%s" is not available', $entityTypeCode) |
325
|
|
|
) |
326
|
|
|
); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* Return's TRUE, if the passed URL key varchar value IS related with the actual PK. |
331
|
|
|
* |
332
|
|
|
* @param array $productVarcharAttribute The varchar value to check |
333
|
|
|
* |
334
|
|
|
* @return boolean TRUE if the URL key is related, else FALSE |
335
|
|
|
*/ |
336
|
|
|
public function isUrlKeyOf(array $productVarcharAttribute) |
337
|
|
|
{ |
338
|
|
|
return ((integer) $productVarcharAttribute[MemberNames::ENTITY_ID] === (integer) $this->getLastEntityId()) && |
339
|
|
|
((integer) $productVarcharAttribute[MemberNames::STORE_ID] === (integer) $this->getRowStoreId(StoreViewCodes::ADMIN)); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Loads and returns the media roles. |
344
|
|
|
* |
345
|
|
|
* @return array The array with the media roles |
346
|
|
|
*/ |
347
|
|
|
public function getMediaRoles(): array |
348
|
|
|
{ |
349
|
|
|
return $this->mediaRolesLoader->load(); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Return's the entity type code to be used. |
354
|
|
|
* |
355
|
|
|
* @return string The entity type code to be used |
356
|
|
|
*/ |
357
|
|
|
public function getEntityTypeCode() |
358
|
|
|
{ |
359
|
|
|
return $this->entityTypeCodeMapper->map(parent::getEntityTypeCode()); |
360
|
|
|
} |
361
|
|
|
} |
362
|
|
|
|
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.