Completed
Push — master ( f011c2...fd1e29 )
by Tim
14s queued 11s
created

AbstractProductSubject::setLastSku()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 1
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
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\Utils\RegistryKeys;
24
use TechDivision\Import\Utils\StoreViewCodes;
25
use TechDivision\Import\Utils\FrontendInputTypes;
26
use TechDivision\Import\Product\Utils\MemberNames;
27
use TechDivision\Import\Product\Utils\RelationTypes;
28
use TechDivision\Import\Product\Utils\ConfigurationKeys;
29
use TechDivision\Import\Subjects\AbstractEavSubject;
30
use TechDivision\Import\Subjects\EntitySubjectInterface;
31
use TechDivision\Import\Product\Exceptions\MapSkuToEntityIdException;
32
use TechDivision\Import\Product\Exceptions\MapLinkTypeCodeToIdException;
33
34
/**
35
 * The abstract product subject implementation that provides basic product
36
 * handling business logic.
37
 *
38
 * @author    Tim Wagner <[email protected]>
39
 * @copyright 2016 TechDivision GmbH <[email protected]>
40
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
41
 * @link      https://github.com/techdivision/import-product
42
 * @link      http://www.techdivision.com
43
 */
44
abstract class AbstractProductSubject extends AbstractEavSubject implements EntitySubjectInterface, SkuToPkMappingAwareSubjectInterface
45
{
46
47
    /**
48
     * The trait with the SKU => PK mapping functionality.
49
     *
50
     * @var \TechDivision\Import\Product\Subjects\SkuToPkMappingTrait
51
     */
52
    use SkuToPkMappingTrait;
53
54
    /**
55
     * The available EAV attributes, grouped by their attribute set and the attribute set name as keys.
56
     *
57
     * @var array
58
     */
59
    protected $attributes = array();
60
61
    /**
62
     * The available tax classes.
63
     *
64
     * @var array
65
     */
66
    protected $taxClasses = array();
67
68
    /**
69
     * The available categories.
70
     *
71
     * @var array
72
     */
73
    protected $categories = array();
74
75
    /**
76
     * The available link types.
77
     *
78
     * @var array
79
     */
80
    protected $linkTypes = array();
81
82
    /**
83
     * The available link attributes.
84
     *
85
     * @var array
86
     */
87
    protected $linkAttributes = array();
88
89
    /**
90
     * The ID of the product that has been created recently.
91
     *
92
     * @var string
93
     */
94
    protected $lastEntityId;
95
96
    /**
97
     * The SKU of the product that has been created recently.
98
     *
99
     * @var string
100
     */
101
    protected $lastSku;
102
103
    /**
104
     * The Magento 2 configuration.
105
     *
106
     * @var array
107
     */
108
    protected $coreConfigData;
109
110
    /**
111
     * The mapping for the SKUs to the created entity IDs.
112
     *
113
     * @var array
114
     */
115
    protected $skuEntityIdMapping = array();
116
117
    /**
118
     * The mapping for the SKUs to the store view codes.
119
     *
120
     * @var array
121
     */
122
    protected $skuStoreViewCodeMapping = array();
123
124
    /**
125
     * The array with the available image types and their label columns.
126
     *
127
     * @var array
128
     */
129
    protected $imageTypes = array();
130
131
    /**
132
     * Mappings for CSV column header => attribute code.
133
     *
134
     * @var array
135
     */
136
    protected $headerMappings = array();
137
138
    /**
139
     * The default mappings for the user defined attributes, based on the attributes frontend input type.
140
     *
141
     * @var array
142
     */
143
    protected $defaultFrontendInputCallbackMappings = array(
144
        FrontendInputTypes::SELECT      => array('import_product.callback.select'),
145
        FrontendInputTypes::MULTISELECT => array('import_product.callback.multiselect'),
146
        FrontendInputTypes::BOOLEAN     => array('import_product.callback.boolean')
147
    );
148
149
    /**
150
     * Array that contains the relations that has already been processed.
151
     *
152
     * @var array
153
     */
154
    protected $processedRelations = array();
155
156
    /**
157
     * The array that contains the prepared link type mappings.
158
     *
159
     * @var array
160
     */
161
    protected $linkTypeMappings = array();
162
163
    /**
164
     * The array that contains the link type => column name prefix mapping.
165
     *
166
     * @var array
167
     */
168
    protected $linkTypeCodeToColumnNameMapping = array('super' => 'associated');
169
170
    /**
171
     * The array that contains the link type attribute column => callback mapping.
172
     *
173
     * @var array
174
     */
175
    protected $linkTypeAttributeColumnToCallbackMapping = array(
176
        'associated_skus' => array('associated_skus', 'explodeKey'),
177
        'associated_qty'  => array('associated_skus', 'explodeValue')
178
    );
179
180
    /**
181
     * The array with the columns that has to be cleaned-up.
182
     *
183
     * @var array
184
     */
185 18
    protected $cleanUpColumns = array();
186
187 18
    /**
188
     * Return's the default callback frontend input mappings for the user defined attributes.
189
     *
190
     * @return array The default frontend input callback mappings
191
     */
192
    public function getDefaultFrontendInputCallbackMappings()
193
    {
194
        return $this->defaultFrontendInputCallbackMappings;
195 18
    }
196
197 18
    /**
198
     * Return's the available link types.
199
     *
200
     * @return array The link types
201
     */
202
    public function getLinkTypes()
203
    {
204
        return $this->linkTypes;
205
    }
206
207
    /**
208
     * Set's the SKU of the last imported product.
209
     *
210
     * @param string $lastSku The SKU
211
     *
212
     * @return void
213
     */
214
    public function setLastSku($lastSku)
215
    {
216
        $this->lastSku = $lastSku;
217
    }
218
219
    /**
220
     * Return's the SKU of the last imported product.
221
     *
222
     * @return string|null The SKU
223
     */
224
    public function getLastSku()
225
    {
226
        return $this->lastSku;
227
    }
228
229
    /**
230
     * Set's the ID of the product that has been created recently.
231
     *
232
     * @param string $lastEntityId The entity ID
233
     *
234
     * @return void
235
     */
236
    public function setLastEntityId($lastEntityId)
237
    {
238
        $this->lastEntityId = $lastEntityId;
239
    }
240
241
    /**
242
     * Return's the ID of the product that has been created recently.
243
     *
244
     * @return string The entity Id
245
     */
246
    public function getLastEntityId()
247
    {
248
        return $this->lastEntityId;
249
    }
250
251
    /**
252
     * Queries whether or not the SKU has already been processed.
253
     *
254
     * @param string $sku The SKU to check been processed
255
     *
256
     * @return boolean TRUE if the SKU has been processed, else FALSE
257
     */
258
    public function hasBeenProcessed($sku)
259
    {
260
        return isset($this->skuEntityIdMapping[$sku]);
261
    }
262
263
    /**
264
     * Queries whether or not the passed PK and store view code has already been processed.
265
     *
266
     * @param string $pk            The PK to check been processed
267
     * @param string $storeViewCode The store view code to check been processed
268
     *
269
     * @return boolean TRUE if the PK and store view code has been processed, else FALSE
270
     */
271
    public function storeViewHasBeenProcessed($pk, $storeViewCode)
272
    {
273
        return isset($this->skuEntityIdMapping[$pk]) && isset($this->skuStoreViewCodeMapping[$pk]) && in_array($storeViewCode, $this->skuStoreViewCodeMapping[$pk]);
274
    }
275
276
    /**
277
     * Add the passed SKU => entity ID mapping.
278
     *
279
     * @param string       $sku      The SKU
280
     * @param integer|null $entityId The optional entity ID, the last processed entity ID is used, if not set
281
     *
282
     * @return void
283
     */
284
    public function addSkuEntityIdMapping($sku, $entityId = null)
285
    {
286
        $this->skuEntityIdMapping[$sku] = $entityId == null ? $this->getLastEntityId() : $entityId;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $entityId of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
287
    }
288
289
    /**
290
     * Add the passed SKU => store view code mapping.
291
     *
292
     * @param string $sku           The SKU
293
     * @param string $storeViewCode The store view code
294
     *
295
     * @return void
296
     */
297
    public function addSkuStoreViewCodeMapping($sku, $storeViewCode)
298
    {
299
        $this->skuStoreViewCodeMapping[$sku][] = $storeViewCode;
300
    }
301
302 18
    /**
303
     * Intializes the previously loaded global data for exactly one bunch.
304
     *
305
     * @param string $serial The serial of the actual import
306 18
     *
307
     * @return void
308
     */
309 18
    public function setUp($serial)
310 18
    {
311 18
312 18
        // load the status of the actual import
313 18
        $status = $this->getRegistryProcessor()->getAttribute(RegistryKeys::STATUS);
314 18
315
        // load the global data we've prepared initially
316
        $this->linkTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::LINK_TYPES];
317 18
        $this->categories = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::CATEGORIES];
318
        $this->taxClasses = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::TAX_CLASSES];
319
        $this->imageTypes =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::IMAGE_TYPES];
320 18
        $this->storeWebsites =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::STORE_WEBSITES];
321 18
        $this->linkAttributes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::LINK_ATTRIBUTES];
322
323
        // prepare the link type mappings
324
        $this->linkTypeMappings = $this->prepareLinkTypeMappings();
325
326
        // prepare the columns that has to be cleaned-up
327
        $this->cleanUpColumns = $this->prepareCleanUpColumns();
328
329
        // invoke the parent method
330
        parent::setUp($serial);
331
    }
332
333
334
    /**
335
     * Clean up the global data after importing the bunch.
336
     *
337
     * @param string $serial The serial of the actual import
338
     *
339
     * @return void
340
     */
341
    public function tearDown($serial)
342
    {
343
344
        // load the registry processor
345
        $registryProcessor = $this->getRegistryProcessor();
346
347
        // update the status
348
        $registryProcessor->mergeAttributesRecursive(
349
            RegistryKeys::STATUS,
350
            array(
351
                RegistryKeys::SKU_ENTITY_ID_MAPPING => $this->skuEntityIdMapping,
352
                RegistryKeys::SKU_STORE_VIEW_CODE_MAPPING => $this->skuStoreViewCodeMapping
353
            )
354
        );
355
356
        // invoke the parent method
357
        parent::tearDown($serial);
358
    }
359
360
    /**
361
     * Return's the available image types.
362
     *
363
     * @return array The array with the available image types
364
     */
365
    public function getImageTypes()
366
    {
367
        return $this->imageTypes;
368
    }
369
370
    /**
371
     * Return's the link type code => colums mapping.
372
     *
373
     * @return array The mapping with the link type codes => colums
374
     */
375
    public function getLinkTypeMappings()
376
    {
377
        return $this->linkTypeMappings;
378
    }
379
380
    /**
381
     * Return's the store ID of the actual row, or of the default store
382
     * if no store view code is set in the CSV file.
383
     *
384
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
385
     *
386
     * @return integer The ID of the actual store
387
     * @throws \Exception Is thrown, if the store with the actual code is not available
388
     */
389
    public function getRowStoreId($default = null)
390
    {
391
392
        // initialize the default store view code, if not passed
393
        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...
394
            $defaultStore = $this->getDefaultStore();
395
            $default = $defaultStore[MemberNames::CODE];
396
        }
397
398
        // load the store view code the create the product/attributes for
399
        $storeViewCode = $this->getStoreViewCode($default);
400
401
        // query whether or not, the requested store is available
402
        if (isset($this->stores[$storeViewCode])) {
403
            return (integer) $this->stores[$storeViewCode][MemberNames::STORE_ID];
404
        }
405
406
        // throw an exception, if not
407
        throw new \Exception(
408
            $this->appendExceptionSuffix(
409
                sprintf('Found invalid store view code %s', $storeViewCode)
410
            )
411
        );
412
    }
413
414
    /**
415
     * Return's the store for the passed store code.
416
     *
417
     * @param string $storeCode The store code to return the store for
418
     *
419
     * @return array The requested store
420
     * @throws \Exception Is thrown, if the requested store is not available
421
     */
422
    public function getStoreByStoreCode($storeCode)
423
    {
424
425
        // query whether or not the store with the passed store code exists
426
        if (isset($this->stores[$storeCode])) {
427
            return $this->stores[$storeCode];
428
        }
429
430
        // throw an exception, if not
431
        throw new \Exception(
432
            $this->appendExceptionSuffix(
433
                sprintf('Found invalid store code %s', $storeCode)
434
            )
435
        );
436
    }
437
438
    /**
439
     * Return's the tax class ID for the passed tax class name.
440
     *
441
     * @param string $taxClassName The tax class name to return the ID for
442
     *
443
     * @return integer The tax class ID
444
     * @throws \Exception Is thrown, if the tax class with the requested name is not available
445
     */
446 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...
447
    {
448
449
        // query whether or not, the requested tax class is available
450
        if (isset($this->taxClasses[$taxClassName])) {
451
            return (integer) $this->taxClasses[$taxClassName][MemberNames::CLASS_ID];
452
        }
453
454
        // throw an exception, if not
455
        throw new \Exception(
456
            $this->appendExceptionSuffix(
457
                sprintf('Found invalid tax class name %s', $taxClassName)
458
            )
459
        );
460
    }
461
462
    /**
463
     * Return's the store website for the passed code.
464
     *
465
     * @param string $code The code of the store website to return the ID for
466
     *
467
     * @return integer The store website ID
468
     * @throws \Exception Is thrown, if the store website with the requested code is not available
469
     */
470 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...
471
    {
472
473
        // query whether or not, the requested store website is available
474
        if (isset($this->storeWebsites[$code])) {
475
            return (integer) $this->storeWebsites[$code][MemberNames::WEBSITE_ID];
476
        }
477
478
        // throw an exception, if not
479
        throw new \Exception(
480
            $this->appendExceptionSuffix(
481
                sprintf('Found invalid website code %s', $code)
482
            )
483
        );
484
    }
485
486
    /**
487
     * Return's the category with the passed path.
488
     *
489
     * @param string $path          The path of the category to return
490
     * @param string $storeViewCode The code of a store view, defaults to admin
491
     *
492
     * @return array The category
493
     * @throws \Exception Is thrown, if the requested category is not available
494
     */
495 View Code Duplication
    public function getCategoryByPath($path, $storeViewCode = StoreViewCodes::ADMIN)
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...
496
    {
497
498
        // load the categories by the passed store view code
499
        $categories = $this->getCategoriesByStoreViewCode($storeViewCode);
500
501
        // query whether or not the category with the passed path exists
502
        if (isset($categories[$path])) {
503
            return $categories[$path];
504
        }
505
506
        // throw an exception, if not
507
        throw new \Exception(
508
            $this->appendExceptionSuffix(
509
                sprintf('Can\'t find category with path %s', $path)
510
            )
511
        );
512
    }
513
514
    /**
515
     * Query's whether or not the category with the passed path is available or not.
516
     *
517
     * @param string $path The path of the category to query
518
     *
519
     * @return boolean TRUE if the category is available, else FALSE
520
     */
521
    public function hasCategoryByPath($path)
522
    {
523
        return isset($this->categories[$path]);
524
    }
525
526
    /**
527
     * Retrieve categories by given store view code.
528
     *
529
     * @param string $storeViewCode The store view code to retrieve the categories for
530
     *
531
     * @return array The array with the categories for the passed store view code
532
     */
533
    public function getCategoriesByStoreViewCode($storeViewCode)
534
    {
535
        return isset($this->categories[$storeViewCode]) ? $this->categories[$storeViewCode] : array();
536
    }
537
538
    /**
539
     * Return's the category with the passed ID.
540
     *
541
     * @param integer $categoryId    The ID of the category to return
542
     * @param string  $storeViewCode The code of a store view, defaults to "admin"
543
     *
544
     * @return array The category data
545
     * @throws \Exception Is thrown, if the category is not available
546
     */
547 View Code Duplication
    public function getCategory($categoryId, $storeViewCode = StoreViewCodes::ADMIN)
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...
548
    {
549
550
        // retrieve the categories with for the passed store view code
551
        $categories = $this->getCategoriesByStoreViewCode($storeViewCode);
552
553
        // try to load the category with the passed ID
554
        foreach ($categories as $category) {
555
            if ($category[MemberNames::ENTITY_ID] == $categoryId) {
556
                return $category;
557
            }
558
        }
559
560
        // throw an exception if the category is NOT available
561
        throw new \Exception(
562
            $this->appendExceptionSuffix(
563
                sprintf('Can\'t load category with ID %d', $categoryId)
564
            )
565
        );
566
    }
567
568
    /**
569
     * Return's the root category for the actual view store.
570
     *
571
     * @return array The store's root category
572
     * @throws \Exception Is thrown if the root category for the passed store code is NOT available
573
     */
574
    public function getRootCategory()
575
    {
576
577
        // load the default store
578
        $defaultStore = $this->getDefaultStore();
579
580
        // load the actual store view code
581
        $storeViewCode = $this->getStoreViewCode($defaultStore[MemberNames::CODE]);
582
583
        // query weather or not we've a root category or not
584
        if (isset($this->rootCategories[$storeViewCode])) {
585
            return $this->rootCategories[$storeViewCode];
586
        }
587
588
        // throw an exception if the root category is NOT available
589
        throw new \Exception(
590
            $this->appendExceptionSuffix(
591
                sprintf('Root category for %s is not available', $storeViewCode)
592
            )
593
        );
594
    }
595
596
    /**
597
     * Returns an array with the codes of the store views related with the passed website code.
598
     *
599
     * @param string $websiteCode The code of the website to return the store view codes for
600
     *
601
     * @return array The array with the matching store view codes
602
     */
603
    public function getStoreViewCodesByWebsiteCode($websiteCode)
604
    {
605
606
        // query whether or not the website with the passed code exists
607
        if (!isset($this->storeWebsites[$websiteCode])) {
608
            // throw an exception if the website is NOT available
609
            throw new \Exception(
610
                $this->appendExceptionSuffix(
611
                    sprintf('Website with code "%s" is not available', $websiteCode)
612
                )
613
            );
614
        }
615
616
        // initialize the array for the store view codes
617
        $storeViewCodes = array();
618
619
        // load the website ID
620
        $websiteId = (integer) $this->storeWebsites[$websiteCode][MemberNames::WEBSITE_ID];
621
622
        // iterate over the available stores to find the one of the website
623
        foreach ($this->stores as $storeCode => $store) {
624
            if ((integer) $store[MemberNames::WEBSITE_ID] === $websiteId) {
625
                $storeViewCodes[] = $storeCode;
626
            }
627
        }
628
629
        // return the array with the matching store view codes
630
        return $storeViewCodes;
631
    }
632
633
    /**
634
     * Merge the columns from the configuration with all image type columns to define which
635
     * columns should be cleaned-up.
636
     *
637
     * @return array The columns that has to be cleaned-up
638
     */
639
    public function getCleanUpColumns()
640
    {
641
        return $this->cleanUpColumns;
642
    }
643
644
    /**
645
     * Marks the relation combination processed.
646
     *
647
     * @param string $key   The key of the relation
648
     * @param string $value One of the relation values
649
     * @param string $type  The relation type to add
650
     *
651
     * @return void
652
     */
653
    public function addProcessedRelation($key, $value, $type = RelationTypes::PRODUCT_RELATION)
654
    {
655
656
        // query whether or not the child SKU has already been processed
657
        if (isset($this->processedRelations[$type][$key])) {
658
            $this->processedRelations[$type][$key][] = $value;
659
        } else {
660
            $this->processedRelations[$type][$key] = array($value);
661
        }
662
    }
663
664
    /**
665
     * Query's whether or not the relation with the passed key
666
     * value combination and the given type has been processed.
667
     *
668
     * @param string $key   The key of the relation
669
     * @param string $value One of the relation values
670
     * @param string $type  The relation type to add
671
     *
672
     * @return boolean TRUE if the combination has been processed, else FALSE
673
     */
674
    public function hasBeenProcessedRelation($key, $value, $type = RelationTypes::PRODUCT_RELATION)
675
    {
676
677
        // query whether or not the parent SKU has already been registered
678
        if (isset($this->processedRelations[$type][$key])) {
679
            return in_array($value, $this->processedRelations[$type][$key]);
680
        }
681
682
        // return FALSE if NOT
683
        return false;
684
    }
685
686
    /**
687
     * Return's the link type ID for the passed link type code.
688
     *
689
     * @param string $linkTypeCode The link type code to return the link type ID for
690
     *
691
     * @return integer The mapped link type ID
692
     * @throws \TechDivision\Import\Product\Exceptions\MapLinkTypeCodeToIdException Is thrown if the link type code is not mapped yet
693
     */
694 View Code Duplication
    public function mapLinkTypeCodeToLinkTypeId($linkTypeCode)
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...
695
    {
696
697
        // query weather or not the link type code has been mapped
698
        if (isset($this->linkTypes[$linkTypeCode])) {
699
            return $this->linkTypes[$linkTypeCode][MemberNames::LINK_TYPE_ID];
700
        }
701
702
        // throw an exception if the link type code has not been mapped yet
703
        throw new MapLinkTypeCodeToIdException(
704
            $this->appendExceptionSuffix(
705
                sprintf('Found not mapped link type code %s', $linkTypeCode)
706
            )
707
        );
708
    }
709
710
    /**
711
     * Return's the link attribute for the passed link type ID and attribute code.
712
     *
713
     * @param integer $linkTypeId    The link type
714
     * @param string  $attributeCode The attribute code
715
     *
716
     * @return array The link attribute
717
     */
718 View Code Duplication
    public function getProductLinkAttribute($linkTypeId, $attributeCode)
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...
719
    {
720
721
        // try to load the link attribute with the passed link type ID and attribute code
722
        foreach ($this->linkAttributes as $linkAttribute) {
723
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId &&
724
                $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE] === $attributeCode
725
            ) {
726
                // return the matching link attribute
727
                return $linkAttribute;
728
            }
729
        }
730
    }
731
732
    /**
733
     * Return's the link attribute for the passed link type and attribute code.
734
     *
735
     * @param string $linkTypeCode  The link type code
736
     * @param string $attributeCode The attribute code
737
     *
738
     * @return array The link attribute
739
     */
740 View Code Duplication
    public function getProductLinkAttributeByLinkTypeCodeAndAttributeCode($linkTypeCode, $attributeCode)
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...
741
    {
742
743
        // map the link type code => ID
744
        $linkTypeId = $this->mapLinkTypeCodeToLinkTypeId($linkTypeCode);
745
746
        // try to load the link attribute with the passed link type ID and attribute code
747
        foreach ($this->linkAttributes as $linkAttribute) {
748
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId &&
749
                $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE] === $attributeCode
750
            ) {
751
                // return the matching link attribute
752
                return $linkAttribute;
753
            }
754
        }
755
    }
756
757
    /**
758
     * Returns the product link attributes for the passed link type code.
759
     *
760
     * @param string $linkTypeCode The link type code
761
     *
762
     * @return array The product link types
763
     */
764
    public function getProductLinkAttributes($linkTypeCode)
765
    {
766
767
        // map the link type code => ID
768
        $linkTypeId = $this->mapLinkTypeCodeToLinkTypeId($linkTypeCode);
769
770
        // initialize the array for the link attributes
771
        $linkAttributes = array();
772
773
        // try to load the link attribute with the passed link type ID and attribute code
774
        foreach ($this->linkAttributes as $linkAttribute) {
775
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId) {
776
                // return the matching link attribute
777
                $linkAttributes[] = $linkAttribute;
778
            }
779
        }
780
781
        // return the link attributes
782
        return $linkAttributes;
783
    }
784
785
    /**
786
     * Maps the link type code to the apropriate column name.
787
     *
788
     * @param string $linkTypeCode The link type code to map
789
     *
790
     * @return string The mapped column name
791
     */
792
    public function mapLinkTypeCodeToColumnName($linkTypeCode)
793
    {
794
795
        // query whether or not the link type code has a mapping
796
        if (isset($this->linkTypeCodeToColumnNameMapping[$linkTypeCode])) {
797
            return $this->linkTypeCodeToColumnNameMapping[$linkTypeCode];
798
        }
799
800
        // return the passed link type code
801
        return $linkTypeCode;
802
    }
803
804
    /**
805
     * Return the entity ID for the passed SKU.
806
     *
807
     * @param string $sku The SKU to return the entity ID for
808
     *
809
     * @return integer The mapped entity ID
810
     * @throws \TechDivision\Import\Product\Exceptions\MapSkuToEntityIdException Is thrown if the SKU is not mapped yet
811
     */
812
    public function mapSkuToEntityId($sku)
813
    {
814
815
        // query weather or not the SKU has been mapped
816
        if (isset($this->skuEntityIdMapping[$sku])) {
817
            return $this->skuEntityIdMapping[$sku];
818
        }
819
820
        // throw an exception if the SKU has not been mapped yet
821
        throw new MapSkuToEntityIdException(
822
            $this->appendExceptionSuffix(
823
                sprintf('Found not mapped entity ID for SKU %s', $sku)
824
            )
825
        );
826
    }
827
828
    /**
829
     * Return's the link type code => colums mapping.
830
     *
831
     * @return array The mapping with the link type codes => colums
832
     */
833
    public function prepareLinkTypeMappings()
834
    {
835
836
        // initialize the array with link type mappings
837
        $linkTypeMappings = array();
838
839
        // prepare the link type mappings
840
        foreach ($this->getLinkTypes() as $linkType) {
841 18
            // map the link type code to the column name, if necessary
842
            $columnName = $this->mapLinkTypeCodeToColumnName($linkType[MemberNames::CODE]);
843
844
            // create the header for the link type mapping
845 18
            $linkTypeMappings[$linkType[MemberNames::CODE]][] = array (
846
                $fullColumnName = sprintf('%s_skus', $columnName),
847
                $this->getLinkTypeColumnCallback($fullColumnName)
848 18
            );
849
850
            // add the mappings for the columns that contains the values for the configured link type attributes
851
            foreach ($this->getProductLinkAttributes($linkType[MemberNames::CODE]) as $linkAttribute) {
852
                // initialize the full column name that uses the column name as prefix and the attribute code as suffix
853
                $fullColumnName = sprintf('%s_%s', $columnName, $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE]);
854
                // load the callback that extracts the values from the columns
855
                $callback = $this->getLinkTypeColumnCallback($fullColumnName);
856
857
                // map the column name to the real column name
858
                if (isset($this->linkTypeAttributeColumnToCallbackMapping[$fullColumnName])) {
859
                    list ($fullColumnName, ) = $this->linkTypeAttributeColumnToCallbackMapping[$fullColumnName];
860
                }
861
862
                // add the link type mapping for the column with the link type value
863
                $linkTypeMappings[$linkType[MemberNames::CODE]][] = array(
864
                    $fullColumnName,
865
                    $callback,
866
                    $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE]
867
                );
868
            }
869
        }
870
871
        // return the link type mappings
872
        return $linkTypeMappings;
873
    }
874
875
    /**
876
     * Return's the columns that has to be cleaned-up.
877
     *
878
     * @return array The mapping with the columns that has to be cleaned-up
879
     */
880 18
    public function prepareCleanUpColumns()
881
    {
882
883
        // initialize the array with the colums that has to be cleaned-up
884
        $cleanUpColumns = array();
885
886
        // try to load the colums that has to be cleaned-up
887
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS)) {
888
            $cleanUpColumns = array_merge(
889
                $cleanUpColumns,
890
                $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS, array())
891
            );
892
        }
893
894
        // query whether or not the image columns has to be cleaned-up also
895 View Code Duplication
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_EMPTY_IMAGE_COLUMNS) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
896
            $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_EMPTY_IMAGE_COLUMNS, false)
897
        ) {
898
            // if yes load the image column names
899
            $imageTypes = array_keys($this->getImageTypes());
900
901
            // and append them to the column names from the configuration
902
            foreach ($imageTypes as $imageAttribute) {
903
                $cleanUpColumns[] = $this->mapAttributeCodeByHeaderMapping($imageAttribute);
904
            }
905
        }
906
907
        // query whether or not the columns with the product links has to be cleaned-up also
908 View Code Duplication
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_LINKS) &&
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
909
            $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_LINKS, false)
910
        ) {
911
            // load the link type mappings
912
            $linkTypeMappings = $this->getLinkTypeMappings();
913
914
            // prepare the links for the found link types and clean up
915
            foreach ($linkTypeMappings as $columns) {
916
                // shift the column with the header information from the stack
917
                list ($columnNameChildSkus, ) = array_shift($columns);
918
                // append the column name from the link type mapping
919
                $cleanUpColumns[] = $columnNameChildSkus;
920
            }
921
        }
922
923
        // return the array with the column names that has to be cleaned-up
924
        return $cleanUpColumns;
925
    }
926
927
    /**
928
     * Returns the callback method used to extract the value of the passed
929
     * column to create the link type attribute value with.
930
     *
931
     * @param string $columnName The column name to create the callback for
932
     *
933
     * @return callable The callback
934
     */
935
    public function getLinkTypeColumnCallback($columnName)
936
    {
937
938
        // query whether or not a callback mapping is available
939
        if (isset($this->linkTypeAttributeColumnToCallbackMapping[$columnName])) {
940
            // load it from the array with the mappings
941
            list (, $callbackName) = $this->linkTypeAttributeColumnToCallbackMapping[$columnName];
942
            // prepare and return the callback
943
            return array($this, $callbackName);
944
        }
945
946
        // return the default callback
947
        return array($this, 'explode');
948
    }
949
950
    /**
951
     * Extracts the keys of the passed value by exploding them
952
     * with the also passed delimiter/value delmiter.
953
     *
954
     * @param string $value          The value to extract
955
     * @param string $delimiter      The delimiter used to extract the elements
956
     * @param string $valueDelimiter The delimiter used to extract the key from the value
957
     *
958
     * @return array The exploded keys
959
     */
960
    public function explodeKey($value, $delimiter = ',', $valueDelimiter = '=')
961
    {
962
963
        // initialize the array for the keys
964
        $keys = array();
965
966
        // extract the keys from the value
967
        foreach ($this->explode($value, $delimiter) as $keyValue) {
968
            // explode the key(s)
969
            $explodedKey = $this->explode($keyValue, $valueDelimiter);
970
            // extract the values of the exploded keys
971
            if (is_array($explodedKey)) {
972
                list ($keys[],) = $explodedKey;
973
            }
974
        }
975
976
        // return the array with the keys
977
        return $keys;
978
    }
979
980
    /**
981
     * Extracts the values of the passed value by exploding them
982
     * with the also passed delimiter/value delimiter.
983
     *
984
     * @param string $value          The value to extract
985
     * @param string $delimiter      The delimiter used to extract the elements
986
     * @param string $valueDelimiter The delimiter used to extract the key from the value
987
     *
988
     * @return array The exploded values
989
     */
990
    public function explodeValue($value, $delimiter = ',', $valueDelimiter = '=')
991
    {
992
993
        // initialize the array for the values
994
        $values = array();
995
996
        // extract the values from the value
997
        foreach ($this->explode($value, $delimiter) as $keyValue) {
998
            // explode the value(s)
999
            $explodedValue = $this->explode($keyValue, $valueDelimiter);
1000
            // extract the values, whether or not two or less has been found
1001
            if (is_array($explodedValue)) {
1002
                if (count($explodedValue) < 2) {
1003
                    $values[] = 0;
1004
                } else {
1005
                    list (, $values[]) = $explodedValue;
1006
                }
1007
            }
1008
        }
1009
1010
        // return the array with the values
1011
        return $values;
1012
    }
1013
}
1014