Completed
Push — master ( c91a75...880ee4 )
by Tim
02:12
created

AbstractProductSubject::setUp()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 39
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.1406

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 39
ccs 9
cts 12
cp 0.75
rs 8.8571
cc 3
eloc 17
nc 2
nop 1
crap 3.1406
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Subjects\AbstractProductSubject
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 TechDivision\Import\Product\Utils\MemberNames;
24
use TechDivision\Import\Subjects\AbstractEavSubject;
25
use TechDivision\Import\Subjects\EntitySubjectInterface;
26
use TechDivision\Import\Utils\FrontendInputTypes;
27
use TechDivision\Import\Utils\RegistryKeys;
28
29
/**
30
 * The abstract product subject implementation that provides basic product
31
 * handling business logic.
32
 *
33
 * @author    Tim Wagner <[email protected]>
34
 * @copyright 2016 TechDivision GmbH <[email protected]>
35
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
36
 * @link      https://github.com/techdivision/import-product
37
 * @link      http://www.techdivision.com
38
 */
39
abstract class AbstractProductSubject extends AbstractEavSubject implements EntitySubjectInterface
40
{
41
42
    /**
43
     * The available stores.
44
     *
45
     * @var array
46
     */
47
    protected $stores = array();
48
49
    /**
50
     * The available store websites.
51
     *
52
     * @var array
53
     */
54
    protected $storeWebsites = array();
55
56
    /**
57
     * The available EAV attributes, grouped by their attribute set and the attribute set name as keys.
58
     *
59
     * @var array
60
     */
61
    protected $attributes = array();
62
63
    /**
64
     * The available tax classes.
65
     *
66
     * @var array
67
     */
68
    protected $taxClasses = array();
69
70
    /**
71
     * The available categories.
72
     *
73
     * @var array
74
     */
75
    protected $categories = array();
76
77
    /**
78
     * The available link types.
79
     *
80
     * @var array
81
     */
82
    protected $linkTypes = array();
83
84
    /**
85
     * The ID of the product that has been created recently.
86
     *
87
     * @var string
88
     */
89
    protected $lastEntityId;
90
91
    /**
92
     * The SKU of the product that has been created recently.
93
     *
94
     * @var string
95
     */
96
    protected $lastSku;
97
98
    /**
99
     * The Magento 2 configuration.
100
     *
101
     * @var array
102
     */
103
    protected $coreConfigData;
104
105
    /**
106
     * The mapping for the SKUs to the created entity IDs.
107
     *
108
     * @var array
109
     */
110
    protected $skuEntityIdMapping = array();
111
112
    /**
113
     * The mapping for the SKUs to the store view codes.
114
     *
115
     * @var array
116
     */
117
    protected $skuStoreViewCodeMapping = array();
118
119
    /**
120
     * The array with the available image types and their label columns.
121
     *
122
     * @var array
123
     */
124
    protected $imageTypes = array();
125
126
    /**
127
     * Mappings for CSV column header => attribute code.
128
     *
129
     * @var array
130
     */
131
    protected $headerMappings = array(
132
        'product_online'       => 'status',
133
        'tax_class_name'       => 'tax_class_id',
134
        'bundle_price_type'    => 'price_type',
135
        'bundle_sku_type'      => 'sku_type',
136
        'bundle_price_view'    => 'price_view',
137
        'bundle_weight_type'   => 'weight_type',
138
        'base_image'           => 'image',
139
        'base_image_label'     => 'image_label',
140
        'thumbnail_image'      => 'thumbnail',
141
        'thumbnail_image_label'=> 'thumbnail_label',
142
        'bundle_shipment_type' => 'shipment_type',
143
        'related_skus'         => 'relation_skus',
144
        'related_position'     => 'relation_position',
145
        'crosssell_skus'       => 'cross_sell_skus',
146
        'crosssell_position'   => 'cross_sell_position',
147
        'upsell_skus'          => 'up_sell_skus',
148
        'upsell_position'      => 'up_sell_position',
149
        'msrp_price'           => 'msrp'
150
    );
151
152
    /**
153
     * The default mappings for the user defined attributes, based on the attributes frontend input type.
154
     *
155
     * @var array
156
     */
157
    protected $defaultFrontendInputCallbackMappings = array(
158
        FrontendInputTypes::SELECT      => 'import_product.callback.select',
159
        FrontendInputTypes::MULTISELECT => 'import_product.callback.multiselect',
160
        FrontendInputTypes::BOOLEAN     => 'import_product.callback.boolean'
161
    );
162
163
    /**
164
     * Return's the default callback frontend input mappings for the user defined attributes.
165
     *
166
     * @return array The default frontend input callback mappings
167
     */
168
    public function getDefaultFrontendInputCallbackMappings()
169
    {
170
        return $this->defaultFrontendInputCallbackMappings;
171
    }
172
173 18
    /**
174
     * Return's the available link types.
175 18
     *
176
     * @return array The link types
177
     */
178
    public function getLinkTypes()
179
    {
180
        return $this->linkTypes;
181
    }
182
183
    /**
184
     * Set's the SKU of the last imported product.
185
     *
186
     * @param string $lastSku The SKU
187
     *
188
     * @return void
189
     */
190
    public function setLastSku($lastSku)
191
    {
192
        $this->lastSku = $lastSku;
193
    }
194
195
    /**
196
     * Return's the SKU of the last imported product.
197
     *
198
     * @return string|null The SKU
199
     */
200
    public function getLastSku()
201
    {
202
        return $this->lastSku;
203
    }
204
205
    /**
206
     * Set's the ID of the product that has been created recently.
207
     *
208
     * @param string $lastEntityId The entity ID
209
     *
210
     * @return void
211
     */
212
    public function setLastEntityId($lastEntityId)
213
    {
214
        $this->lastEntityId = $lastEntityId;
215
    }
216
217
    /**
218
     * Return's the ID of the product that has been created recently.
219
     *
220
     * @return string The entity Id
221
     */
222
    public function getLastEntityId()
223
    {
224
        return $this->lastEntityId;
225
    }
226
227
    /**
228
     * Queries whether or not the SKU has already been processed.
229
     *
230
     * @param string $sku The SKU to check been processed
231
     *
232
     * @return boolean TRUE if the SKU has been processed, else FALSE
233
     */
234
    public function hasBeenProcessed($sku)
235
    {
236
        return isset($this->skuEntityIdMapping[$sku]);
237
    }
238
239
    /**
240
     * Queries whether or not the passed PK and store view code has already been processed.
241
     *
242
     * @param string $pk            The PK to check been processed
243
     * @param string $storeViewCode The store view code to check been processed
244
     *
245
     * @return boolean TRUE if the PK and store view code has been processed, else FALSE
246
     */
247
    public function storeViewHasBeenProcessed($pk, $storeViewCode)
248
    {
249
        return isset($this->skuEntityIdMapping[$pk]) && isset($this->skuStoreViewCodeMapping[$pk]) && in_array($storeViewCode, $this->skuStoreViewCodeMapping[$pk]);
250
    }
251
252
    /**
253
     * Add the passed SKU => entity ID mapping.
254
     *
255
     * @param string $sku The SKU
256
     *
257
     * @return void
258
     */
259
    public function addSkuEntityIdMapping($sku)
260
    {
261
        $this->skuEntityIdMapping[$sku] = $this->getLastEntityId();
262
    }
263
264
    /**
265
     * Add the passed SKU => store view code mapping.
266
     *
267
     * @param string $sku           The SKU
268
     * @param string $storeViewCode The store view code
269
     *
270
     * @return void
271
     */
272
    public function addSkuStoreViewCodeMapping($sku, $storeViewCode)
273
    {
274
        $this->skuStoreViewCodeMapping[$sku][] = $storeViewCode;
275
    }
276
277
    /**
278
     * Intializes the previously loaded global data for exactly one bunch.
279
     *
280
     * @param string $serial The serial of the actual import
281
     *
282
     * @return void
283
     */
284
    public function setUp($serial)
285
    {
286
287
        // load the status of the actual import
288
        $status = $this->getRegistryProcessor()->getAttribute($serial);
289 18
290
        // load the global data we've prepared initially
291
        $this->linkTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::LINK_TYPES];
292
        $this->categories = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::CATEGORIES];
293 18
        $this->taxClasses = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::TAX_CLASSES];
294
        $this->storeWebsites =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::STORE_WEBSITES];
295
        $this->imageTypes =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::IMAGE_TYPES];
296 18
297 18
        // merge the image types with the values found in the configuration
298 18
        $this->imageTypes = array_merge($this->imageTypes, $this->getConfiguration()->getImageTypes());
299 18
300
        // extend the header mappings, if image types has been found
301
        if (sizeof($this->imageTypes) > 0) {
302 18
            // initialize the array for the header mappings
303
            $imageTypeHeaderMappings = array();
304
305 18
            // iterate over the image types and extend the header mappings
306 18
            foreach ($this->imageTypes as $value) {
307
                // load the image and the image label
308
                $valueImage = $value . '_image';
309
                $valueImageLabel = $value . '_image_label';
310
311
                // extend the header mappings for the image type/label
312
                $imageTypeHeaderMappings[$valueImage] = $value;
313
                $imageTypeHeaderMappings[$valueImageLabel] = $value . '_label';
314
            }
315
316
            // extend the header mappings with the header mappings for the image types
317
            $this->headerMappings = array_merge($this->headerMappings, $imageTypeHeaderMappings);
318
        }
319
320
        // invoke the parent method
321
        parent::setUp($serial);
322
    }
323
324
325
    /**
326
     * Clean up the global data after importing the bunch.
327
     *
328
     * @param string $serial The serial of the actual import
329
     *
330
     * @return void
331
     */
332
    public function tearDown($serial)
333
    {
334
335
        // invoke the parent method
336
        parent::tearDown($serial);
337
338
        // load the registry processor
339
        $registryProcessor = $this->getRegistryProcessor();
340
341
        // update the status
342
        $registryProcessor->mergeAttributesRecursive(
343
            $serial,
344
            array(
345
                RegistryKeys::FILES => array($this->getFilename() => array(RegistryKeys::STATUS => 1)),
346
                RegistryKeys::SKU_ENTITY_ID_MAPPING => $this->skuEntityIdMapping,
347
                RegistryKeys::SKU_STORE_VIEW_CODE_MAPPING => $this->skuStoreViewCodeMapping
348
            )
349
        );
350
    }
351
352
    /**
353
     * Return's the available image types.
354
     *
355
     * @return array The array with the available image types
356
     */
357
    public function getImageTypes()
358
    {
359
        return $this->imageTypes;
360
    }
361
362
    /**
363
     * Return's the store ID of the actual row, or of the default store
364
     * if no store view code is set in the CSV file.
365
     *
366
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
367
     *
368
     * @return integer The ID of the actual store
369
     * @throws \Exception Is thrown, if the store with the actual code is not available
370
     */
371
    public function getRowStoreId($default = null)
372
    {
373
374
        // initialize the default store view code, if not passed
375
        if ($default == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $default of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
376
            $defaultStore = $this->getDefaultStore();
377
            $default = $defaultStore[MemberNames::CODE];
378
        }
379
380
        // load the store view code the create the product/attributes for
381
        $storeViewCode = $this->getStoreViewCode($default);
382
383
        // query whether or not, the requested store is available
384
        if (isset($this->stores[$storeViewCode])) {
385
            return (integer) $this->stores[$storeViewCode][MemberNames::STORE_ID];
386
        }
387
388
        // throw an exception, if not
389
        throw new \Exception(
390
            $this->appendExceptionSuffix(
391
                sprintf('Found invalid store view code %s', $storeViewCode)
392
            )
393
        );
394
    }
395
396
    /**
397
     * Return's the tax class ID for the passed tax class name.
398
     *
399
     * @param string $taxClassName The tax class name to return the ID for
400
     *
401
     * @return integer The tax class ID
402
     * @throws \Exception Is thrown, if the tax class with the requested name is not available
403
     */
404 View Code Duplication
    public function getTaxClassIdByTaxClassName($taxClassName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
405
    {
406
407
        // query whether or not, the requested tax class is available
408
        if (isset($this->taxClasses[$taxClassName])) {
409
            return (integer) $this->taxClasses[$taxClassName][MemberNames::CLASS_ID];
410
        }
411
412
        // throw an exception, if not
413
        throw new \Exception(
414
            $this->appendExceptionSuffix(
415
                sprintf('Found invalid tax class name %s', $taxClassName)
416
            )
417
        );
418
    }
419
420
    /**
421
     * Return's the store website for the passed code.
422
     *
423
     * @param string $code The code of the store website to return the ID for
424
     *
425
     * @return integer The store website ID
426
     * @throws \Exception Is thrown, if the store website with the requested code is not available
427
     */
428 View Code Duplication
    public function getStoreWebsiteIdByCode($code)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
429
    {
430
431
        // query whether or not, the requested store website is available
432
        if (isset($this->storeWebsites[$code])) {
433
            return (integer) $this->storeWebsites[$code][MemberNames::WEBSITE_ID];
434
        }
435
436
        // throw an exception, if not
437
        throw new \Exception(
438
            $this->appendExceptionSuffix(
439
                sprintf('Found invalid website code %s', $code)
440
            )
441
        );
442
    }
443
444
    /**
445
     * Return's the category with the passed path.
446
     *
447
     * @param string $path The path of the category to return
448
     *
449
     * @return array The category
450
     * @throws \Exception Is thrown, if the requested category is not available
451
     */
452
    public function getCategoryByPath($path)
453
    {
454
455
        // query whether or not the category with the passed path exists
456
        if (isset($this->categories[$path])) {
457
            return $this->categories[$path];
458
        }
459
460
        // throw an exception, if not
461
        throw new \Exception(
462
            $this->appendExceptionSuffix(
463
                sprintf('Can\'t find category with path %s', $path)
464
            )
465
        );
466
    }
467
468
    /**
469
     * Return's the category with the passed ID.
470
     *
471
     * @param integer $categoryId The ID of the category to return
472
     *
473
     * @return array The category data
474
     * @throws \Exception Is thrown, if the category is not available
475
     */
476
    public function getCategory($categoryId)
477
    {
478
479
        // try to load the category with the passed ID
480
        foreach ($this->categories as $category) {
481
            if ($category[MemberNames::ENTITY_ID] == $categoryId) {
482
                return $category;
483
            }
484
        }
485
486
        // throw an exception if the category is NOT available
487
        throw new \Exception(
488
            $this->appendExceptionSuffix(
489
                sprintf('Can\'t load category with ID %d', $categoryId)
490
            )
491
        );
492
    }
493
494
    /**
495
     * Return's the root category for the actual view store.
496
     *
497
     * @return array The store's root category
498
     * @throws \Exception Is thrown if the root category for the passed store code is NOT available
499
     */
500
    public function getRootCategory()
501
    {
502
503
        // load the default store
504
        $defaultStore = $this->getDefaultStore();
505
506
        // load the actual store view code
507
        $storeViewCode = $this->getStoreViewCode($defaultStore[MemberNames::CODE]);
508
509
        // query weather or not we've a root category or not
510
        if (isset($this->rootCategories[$storeViewCode])) {
511
            return $this->rootCategories[$storeViewCode];
512
        }
513
514
        // throw an exception if the root category is NOT available
515
        throw new \Exception(
516
            $this->appendExceptionSuffix(
517
                sprintf('Root category for %s is not available', $storeViewCode)
518
            )
519
        );
520
    }
521
522
    /**
523
     * Returns an array with the codes of the store views related with the passed website code.
524
     *
525
     * @param string $websiteCode The code of the website to return the store view codes for
526
     *
527
     * @return array The array with the matching store view codes
528
     */
529
    public function getStoreViewCodesByWebsiteCode($websiteCode)
530
    {
531
532
        // query whether or not the website with the passed code exists
533
        if (!isset($this->storeWebsites[$websiteCode])) {
534
            // throw an exception if the website is NOT available
535
            throw new \Exception(
536
                $this->appendExceptionSuffix(
537
                    sprintf('Website with code "%s" is not available', $websiteCode)
538
                )
539
            );
540
        }
541
542
        // initialize the array for the store view codes
543
        $storeViewCodes = array();
544
545
        // load the website ID
546
        $websiteId = (integer) $this->storeWebsites[$websiteCode][MemberNames::WEBSITE_ID];
547
548
        // iterate over the available stores to find the one of the website
549
        foreach ($this->stores as $storeCode => $store) {
550
            if ((integer) $store[MemberNames::WEBSITE_ID] === $websiteId) {
551
                $storeViewCodes[] = $storeCode;
552
            }
553
        }
554
555
        // return the array with the matching store view codes
556
        return $storeViewCodes;
557
    }
558
}
559