Completed
Push — pac-302--remove-related-links-... ( b5ce9a...1e858a )
by Tim
08:40
created

getTaxClassIdByTaxClassName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 15
Ratio 100 %

Importance

Changes 0
Metric Value
dl 15
loc 15
rs 9.7666
c 0
b 0
f 0
cc 2
nc 2
nop 1
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
     * Return's the default callback frontend input mappings for the user defined attributes.
182
     *
183
     * @return array The default frontend input callback mappings
184
     */
185
    public function getDefaultFrontendInputCallbackMappings()
186
    {
187
        return $this->defaultFrontendInputCallbackMappings;
188
    }
189
190
    /**
191
     * Return's the available link types.
192
     *
193
     * @return array The link types
194
     */
195
    public function getLinkTypes()
196
    {
197
        return $this->linkTypes;
198
    }
199
200
    /**
201
     * Set's the SKU of the last imported product.
202
     *
203
     * @param string $lastSku The SKU
204
     *
205
     * @return void
206
     */
207
    public function setLastSku($lastSku)
208
    {
209
        $this->lastSku = $lastSku;
210
    }
211
212
    /**
213
     * Return's the SKU of the last imported product.
214
     *
215
     * @return string|null The SKU
216
     */
217
    public function getLastSku()
218
    {
219
        return $this->lastSku;
220
    }
221
222
    /**
223
     * Set's the ID of the product that has been created recently.
224
     *
225
     * @param string $lastEntityId The entity ID
226
     *
227
     * @return void
228
     */
229
    public function setLastEntityId($lastEntityId)
230
    {
231
        $this->lastEntityId = $lastEntityId;
232
    }
233
234
    /**
235
     * Return's the ID of the product that has been created recently.
236
     *
237
     * @return string The entity Id
238
     */
239
    public function getLastEntityId()
240
    {
241
        return $this->lastEntityId;
242
    }
243
244
    /**
245
     * Queries whether or not the SKU has already been processed.
246
     *
247
     * @param string $sku The SKU to check been processed
248
     *
249
     * @return boolean TRUE if the SKU has been processed, else FALSE
250
     */
251
    public function hasBeenProcessed($sku)
252
    {
253
        return isset($this->skuEntityIdMapping[$sku]);
254
    }
255
256
    /**
257
     * Queries whether or not the passed PK and store view code has already been processed.
258
     *
259
     * @param string $pk            The PK to check been processed
260
     * @param string $storeViewCode The store view code to check been processed
261
     *
262
     * @return boolean TRUE if the PK and store view code has been processed, else FALSE
263
     */
264
    public function storeViewHasBeenProcessed($pk, $storeViewCode)
265
    {
266
        return isset($this->skuEntityIdMapping[$pk]) && isset($this->skuStoreViewCodeMapping[$pk]) && in_array($storeViewCode, $this->skuStoreViewCodeMapping[$pk]);
267
    }
268
269
    /**
270
     * Add the passed SKU => entity ID mapping.
271
     *
272
     * @param string       $sku      The SKU
273
     * @param integer|null $entityId The optional entity ID, the last processed entity ID is used, if not set
274
     *
275
     * @return void
276
     */
277
    public function addSkuEntityIdMapping($sku, $entityId = null)
278
    {
279
        $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...
280
    }
281
282
    /**
283
     * Add the passed SKU => store view code mapping.
284
     *
285
     * @param string $sku           The SKU
286
     * @param string $storeViewCode The store view code
287
     *
288
     * @return void
289
     */
290
    public function addSkuStoreViewCodeMapping($sku, $storeViewCode)
291
    {
292
        $this->skuStoreViewCodeMapping[$sku][] = $storeViewCode;
293
    }
294
295
    /**
296
     * Intializes the previously loaded global data for exactly one bunch.
297
     *
298
     * @param string $serial The serial of the actual import
299
     *
300
     * @return void
301
     */
302
    public function setUp($serial)
303
    {
304
305
        // load the status of the actual import
306
        $status = $this->getRegistryProcessor()->getAttribute(RegistryKeys::STATUS);
307
308
        // load the global data we've prepared initially
309
        $this->linkTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::LINK_TYPES];
310
        $this->categories = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::CATEGORIES];
311
        $this->taxClasses = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::TAX_CLASSES];
312
        $this->imageTypes =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::IMAGE_TYPES];
313
        $this->storeWebsites =  $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::STORE_WEBSITES];
314
        $this->linkAttributes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::LINK_ATTRIBUTES];
315
316
        // prepare the link type mappings
317
        $this->linkTypeMappings = $this->prepareLinkTypeMappings();
318
319
        // invoke the parent method
320
        parent::setUp($serial);
321
    }
322
323
324
    /**
325
     * Clean up the global data after importing the bunch.
326
     *
327
     * @param string $serial The serial of the actual import
328
     *
329
     * @return void
330
     */
331
    public function tearDown($serial)
332
    {
333
334
        // load the registry processor
335
        $registryProcessor = $this->getRegistryProcessor();
336
337
        // update the status
338
        $registryProcessor->mergeAttributesRecursive(
339
            RegistryKeys::STATUS,
340
            array(
341
                RegistryKeys::SKU_ENTITY_ID_MAPPING => $this->skuEntityIdMapping,
342
                RegistryKeys::SKU_STORE_VIEW_CODE_MAPPING => $this->skuStoreViewCodeMapping
343
            )
344
        );
345
346
        // invoke the parent method
347
        parent::tearDown($serial);
348
    }
349
350
    /**
351
     * Return's the available image types.
352
     *
353
     * @return array The array with the available image types
354
     */
355
    public function getImageTypes()
356
    {
357
        return $this->imageTypes;
358
    }
359
360
    /**
361
     * Return's the link type code => colums mapping.
362
     *
363
     * @return array The mapping with the link type codes => colums
364
     */
365
    public function getLinkTypeMappings()
366
    {
367
        return $this->linkTypeMappings;
368
    }
369
370
    /**
371
     * Return's the store ID of the actual row, or of the default store
372
     * if no store view code is set in the CSV file.
373
     *
374
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
375
     *
376
     * @return integer The ID of the actual store
377
     * @throws \Exception Is thrown, if the store with the actual code is not available
378
     */
379
    public function getRowStoreId($default = null)
380
    {
381
382
        // initialize the default store view code, if not passed
383
        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...
384
            $defaultStore = $this->getDefaultStore();
385
            $default = $defaultStore[MemberNames::CODE];
386
        }
387
388
        // load the store view code the create the product/attributes for
389
        $storeViewCode = $this->getStoreViewCode($default);
390
391
        // query whether or not, the requested store is available
392
        if (isset($this->stores[$storeViewCode])) {
393
            return (integer) $this->stores[$storeViewCode][MemberNames::STORE_ID];
394
        }
395
396
        // throw an exception, if not
397
        throw new \Exception(
398
            $this->appendExceptionSuffix(
399
                sprintf('Found invalid store view code %s', $storeViewCode)
400
            )
401
        );
402
    }
403
404
    /**
405
     * Return's the store for the passed store code.
406
     *
407
     * @param string $storeCode The store code to return the store for
408
     *
409
     * @return array The requested store
410
     * @throws \Exception Is thrown, if the requested store is not available
411
     */
412
    public function getStoreByStoreCode($storeCode)
413
    {
414
415
        // query whether or not the store with the passed store code exists
416
        if (isset($this->stores[$storeCode])) {
417
            return $this->stores[$storeCode];
418
        }
419
420
        // throw an exception, if not
421
        throw new \Exception(
422
            $this->appendExceptionSuffix(
423
                sprintf('Found invalid store code %s', $storeCode)
424
            )
425
        );
426
    }
427
428
    /**
429
     * Return's the tax class ID for the passed tax class name.
430
     *
431
     * @param string $taxClassName The tax class name to return the ID for
432
     *
433
     * @return integer The tax class ID
434
     * @throws \Exception Is thrown, if the tax class with the requested name is not available
435
     */
436 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...
437
    {
438
439
        // query whether or not, the requested tax class is available
440
        if (isset($this->taxClasses[$taxClassName])) {
441
            return (integer) $this->taxClasses[$taxClassName][MemberNames::CLASS_ID];
442
        }
443
444
        // throw an exception, if not
445
        throw new \Exception(
446
            $this->appendExceptionSuffix(
447
                sprintf('Found invalid tax class name %s', $taxClassName)
448
            )
449
        );
450
    }
451
452
    /**
453
     * Return's the store website for the passed code.
454
     *
455
     * @param string $code The code of the store website to return the ID for
456
     *
457
     * @return integer The store website ID
458
     * @throws \Exception Is thrown, if the store website with the requested code is not available
459
     */
460 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...
461
    {
462
463
        // query whether or not, the requested store website is available
464
        if (isset($this->storeWebsites[$code])) {
465
            return (integer) $this->storeWebsites[$code][MemberNames::WEBSITE_ID];
466
        }
467
468
        // throw an exception, if not
469
        throw new \Exception(
470
            $this->appendExceptionSuffix(
471
                sprintf('Found invalid website code %s', $code)
472
            )
473
        );
474
    }
475
476
    /**
477
     * Return's the category with the passed path.
478
     *
479
     * @param string $path          The path of the category to return
480
     * @param string $storeViewCode The code of a store view, defaults to admin
481
     *
482
     * @return array The category
483
     * @throws \Exception Is thrown, if the requested category is not available
484
     */
485 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...
486
    {
487
488
        // load the categories by the passed store view code
489
        $categories = $this->getCategoriesByStoreViewCode($storeViewCode);
490
491
        // query whether or not the category with the passed path exists
492
        if (isset($categories[$path])) {
493
            return $categories[$path];
494
        }
495
496
        // throw an exception, if not
497
        throw new \Exception(
498
            $this->appendExceptionSuffix(
499
                sprintf('Can\'t find category with path %s', $path)
500
            )
501
        );
502
    }
503
504
    /**
505
     * Query's whether or not the category with the passed path is available or not.
506
     *
507
     * @param string $path The path of the category to query
508
     *
509
     * @return boolean TRUE if the category is available, else FALSE
510
     */
511
    public function hasCategoryByPath($path)
512
    {
513
        return isset($this->categories[$path]);
514
    }
515
516
    /**
517
     * Retrieve categories by given store view code.
518
     *
519
     * @param string $storeViewCode The store view code to retrieve the categories for
520
     *
521
     * @return array The array with the categories for the passed store view code
522
     */
523
    public function getCategoriesByStoreViewCode($storeViewCode)
524
    {
525
        return isset($this->categories[$storeViewCode]) ? $this->categories[$storeViewCode] : array();
526
    }
527
528
    /**
529
     * Return's the category with the passed ID.
530
     *
531
     * @param integer $categoryId    The ID of the category to return
532
     * @param string  $storeViewCode The code of a store view, defaults to "admin"
533
     *
534
     * @return array The category data
535
     * @throws \Exception Is thrown, if the category is not available
536
     */
537 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...
538
    {
539
540
        // retrieve the categories with for the passed store view code
541
        $categories = $this->getCategoriesByStoreViewCode($storeViewCode);
542
543
        // try to load the category with the passed ID
544
        foreach ($categories as $category) {
545
            if ($category[MemberNames::ENTITY_ID] == $categoryId) {
546
                return $category;
547
            }
548
        }
549
550
        // throw an exception if the category is NOT available
551
        throw new \Exception(
552
            $this->appendExceptionSuffix(
553
                sprintf('Can\'t load category with ID %d', $categoryId)
554
            )
555
        );
556
    }
557
558
    /**
559
     * Return's the root category for the actual view store.
560
     *
561
     * @return array The store's root category
562
     * @throws \Exception Is thrown if the root category for the passed store code is NOT available
563
     */
564
    public function getRootCategory()
565
    {
566
567
        // load the default store
568
        $defaultStore = $this->getDefaultStore();
569
570
        // load the actual store view code
571
        $storeViewCode = $this->getStoreViewCode($defaultStore[MemberNames::CODE]);
572
573
        // query weather or not we've a root category or not
574
        if (isset($this->rootCategories[$storeViewCode])) {
575
            return $this->rootCategories[$storeViewCode];
576
        }
577
578
        // throw an exception if the root category is NOT available
579
        throw new \Exception(
580
            $this->appendExceptionSuffix(
581
                sprintf('Root category for %s is not available', $storeViewCode)
582
            )
583
        );
584
    }
585
586
    /**
587
     * Returns an array with the codes of the store views related with the passed website code.
588
     *
589
     * @param string $websiteCode The code of the website to return the store view codes for
590
     *
591
     * @return array The array with the matching store view codes
592
     */
593
    public function getStoreViewCodesByWebsiteCode($websiteCode)
594
    {
595
596
        // query whether or not the website with the passed code exists
597
        if (!isset($this->storeWebsites[$websiteCode])) {
598
            // throw an exception if the website is NOT available
599
            throw new \Exception(
600
                $this->appendExceptionSuffix(
601
                    sprintf('Website with code "%s" is not available', $websiteCode)
602
                )
603
            );
604
        }
605
606
        // initialize the array for the store view codes
607
        $storeViewCodes = array();
608
609
        // load the website ID
610
        $websiteId = (integer) $this->storeWebsites[$websiteCode][MemberNames::WEBSITE_ID];
611
612
        // iterate over the available stores to find the one of the website
613
        foreach ($this->stores as $storeCode => $store) {
614
            if ((integer) $store[MemberNames::WEBSITE_ID] === $websiteId) {
615
                $storeViewCodes[] = $storeCode;
616
            }
617
        }
618
619
        // return the array with the matching store view codes
620
        return $storeViewCodes;
621
    }
622
623
    /**
624
     * Merge the columns from the configuration with all image type columns to define which
625
     * columns should be cleaned-up.
626
     *
627
     * @return array The columns that has to be cleaned-up
628
     */
629
    public function getCleanUpColumns()
630
    {
631
632
        // load the colums that has to be cleaned-up
633
        $cleanUpColumns = $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS);
634
635
        // query whether or not the image columns has to be cleaned-up also
636 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...
637
            $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_EMPTY_IMAGE_COLUMNS, false)
638
        ) {
639
            // if yes load the image column names
640
            $imageTypes = array_keys($this->getImageTypes());
641
642
            // and append them to the column names from the configuration
643
            foreach ($imageTypes as $imageAttribute) {
644
                $cleanUpColumns[] = $this->mapAttributeCodeByHeaderMapping($imageAttribute);
645
            }
646
        }
647
648
        // query whether or not the columns with the product links has to be cleaned-up also
649 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...
650
            $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_LINKS, false)
651
        ) {
652
            // load the link type mappings
653
            $linkTypeMappings = $this->getLinkTypeMappings();
654
655
            // prepare the links for the found link types and clean up
656
            foreach ($linkTypeMappings as $columns) {
657
                // shift the column with the header information from the stack
658
                list ($columnNameChildSkus, ) = array_shift($columns);
659
                // append the column name from the link type mapping
660
                $cleanUpColumns[] = $columnNameChildSkus;
661
            }
662
        }
663
664
        // return the array with the column names that has to be cleaned-up
665
        return $cleanUpColumns;
666
    }
667
668
    /**
669
     * Marks the relation combination processed.
670
     *
671
     * @param string $key   The key of the relation
672
     * @param string $value One of the relation values
673
     * @param string $type  The relation type to add
674
     *
675
     * @return void
676
     */
677
    public function addProcessedRelation($key, $value, $type = RelationTypes::PRODUCT_RELATION)
678
    {
679
680
        // query whether or not the child SKU has already been processed
681
        if (isset($this->processedRelations[$type][$key])) {
682
            $this->processedRelations[$type][$key][] = $value;
683
        } else {
684
            $this->processedRelations[$type][$key] = array($value);
685
        }
686
    }
687
688
    /**
689
     * Query's whether or not the relation with the passed key
690
     * value combination and the given type has been processed.
691
     *
692
     * @param string $key   The key of the relation
693
     * @param string $value One of the relation values
694
     * @param string $type  The relation type to add
695
     *
696
     * @return boolean TRUE if the combination has been processed, else FALSE
697
     */
698
    public function hasBeenProcessedRelation($key, $value, $type = RelationTypes::PRODUCT_RELATION)
699
    {
700
701
        // query whether or not the parent SKU has already been registered
702
        if (isset($this->processedRelations[$type][$key])) {
703
            return in_array($value, $this->processedRelations[$type][$key]);
704
        }
705
706
        // return FALSE if NOT
707
        return false;
708
    }
709
710
    /**
711
     * Return's the link type ID for the passed link type code.
712
     *
713
     * @param string $linkTypeCode The link type code to return the link type ID for
714
     *
715
     * @return integer The mapped link type ID
716
     * @throws \TechDivision\Import\Product\Exceptions\MapLinkTypeCodeToIdException Is thrown if the link type code is not mapped yet
717
     */
718 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...
719
    {
720
721
        // query weather or not the link type code has been mapped
722
        if (isset($this->linkTypes[$linkTypeCode])) {
723
            return $this->linkTypes[$linkTypeCode][MemberNames::LINK_TYPE_ID];
724
        }
725
726
        // throw an exception if the link type code has not been mapped yet
727
        throw new MapLinkTypeCodeToIdException(
728
            $this->appendExceptionSuffix(
729
                sprintf('Found not mapped link type code %s', $linkTypeCode)
730
            )
731
        );
732
    }
733
734
    /**
735
     * Return's the link attribute for the passed link type ID and attribute code.
736
     *
737
     * @param integer $linkTypeId    The link type
738
     * @param string  $attributeCode The attribute code
739
     *
740
     * @return array The link attribute
741
     */
742 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...
743
    {
744
745
        // try to load the link attribute with the passed link type ID and attribute code
746
        foreach ($this->linkAttributes as $linkAttribute) {
747
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId &&
748
                $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE] === $attributeCode
749
            ) {
750
                // return the matching link attribute
751
                return $linkAttribute;
752
            }
753
        }
754
    }
755
756
    /**
757
     * Return's the link attribute for the passed link type and attribute code.
758
     *
759
     * @param string $linkTypeCode  The link type code
760
     * @param string $attributeCode The attribute code
761
     *
762
     * @return array The link attribute
763
     */
764 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...
765
    {
766
767
        // map the link type code => ID
768
        $linkTypeId = $this->mapLinkTypeCodeToLinkTypeId($linkTypeCode);
769
770
        // try to load the link attribute with the passed link type ID and attribute code
771
        foreach ($this->linkAttributes as $linkAttribute) {
772
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId &&
773
                $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE] === $attributeCode
774
            ) {
775
                // return the matching link attribute
776
                return $linkAttribute;
777
            }
778
        }
779
    }
780
781
    /**
782
     * Returns the product link attributes for the passed link type code.
783
     *
784
     * @param string $linkTypeCode The link type code
785
     *
786
     * @return array The product link types
787
     */
788
    public function getProductLinkAttributes($linkTypeCode)
789
    {
790
791
        // map the link type code => ID
792
        $linkTypeId = $this->mapLinkTypeCodeToLinkTypeId($linkTypeCode);
793
794
        // initialize the array for the link attributes
795
        $linkAttributes = array();
796
797
        // try to load the link attribute with the passed link type ID and attribute code
798
        foreach ($this->linkAttributes as $linkAttribute) {
799
            if ($linkAttribute[MemberNames::LINK_TYPE_ID] === $linkTypeId) {
800
                // return the matching link attribute
801
                $linkAttributes[] = $linkAttribute;
802
            }
803
        }
804
805
        // return the link attributes
806
        return $linkAttributes;
807
    }
808
809
    /**
810
     * Maps the link type code to the apropriate column name.
811
     *
812
     * @param string $linkTypeCode The link type code to map
813
     *
814
     * @return string The mapped column name
815
     */
816
    public function mapLinkTypeCodeToColumnName($linkTypeCode)
817
    {
818
819
        // query whether or not the link type code has a mapping
820
        if (isset($this->linkTypeCodeToColumnNameMapping[$linkTypeCode])) {
821
            return $this->linkTypeCodeToColumnNameMapping[$linkTypeCode];
822
        }
823
824
        // return the passed link type code
825
        return $linkTypeCode;
826
    }
827
828
    /**
829
     * Return the entity ID for the passed SKU.
830
     *
831
     * @param string $sku The SKU to return the entity ID for
832
     *
833
     * @return integer The mapped entity ID
834
     * @throws \TechDivision\Import\Product\Exceptions\MapSkuToEntityIdException Is thrown if the SKU is not mapped yet
835
     */
836
    public function mapSkuToEntityId($sku)
837
    {
838
839
        // query weather or not the SKU has been mapped
840
        if (isset($this->skuEntityIdMapping[$sku])) {
841
            return $this->skuEntityIdMapping[$sku];
842
        }
843
844
        // throw an exception if the SKU has not been mapped yet
845
        throw new MapSkuToEntityIdException(
846
            $this->appendExceptionSuffix(
847
                sprintf('Found not mapped entity ID for SKU %s', $sku)
848
            )
849
        );
850
    }
851
852
    /**
853
     * Return's the link type code => colums mapping.
854
     *
855
     * @return array The mapping with the link type codes => colums
856
     */
857
    public function prepareLinkTypeMappings()
858
    {
859
860
        // initialize the array with link type mappings
861
        $linkTypeMappings = array();
862
863
        // prepare the link type mappings
864
        foreach ($this->getLinkTypes() as $linkType) {
865
            // map the link type code to the column name, if necessary
866
            $columnName = $this->mapLinkTypeCodeToColumnName($linkType[MemberNames::CODE]);
867
868
            // create the header for the link type mapping
869
            $linkTypeMappings[$linkType[MemberNames::CODE]][] = array (
870
                $fullColumnName = sprintf('%s_skus', $columnName),
871
                $this->getLinkTypeColumnCallback($fullColumnName)
872
            );
873
874
            // add the mappings for the columns that contains the values for the configured link type attributes
875
            foreach ($this->getProductLinkAttributes($linkType[MemberNames::CODE]) as $linkAttribute) {
876
                // initialize the full column name that uses the column name as prefix and the attribute code as suffix
877
                $fullColumnName = sprintf('%s_%s', $columnName, $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE]);
878
                // load the callback that extracts the values from the columns
879
                $callback = $this->getLinkTypeColumnCallback($fullColumnName);
880
881
                // map the column name to the real column name
882
                if (isset($this->linkTypeAttributeColumnToCallbackMapping[$fullColumnName])) {
883
                    list ($fullColumnName, ) = $this->linkTypeAttributeColumnToCallbackMapping[$fullColumnName];
884
                }
885
886
                // add the link type mapping for the column with the link type value
887
                $linkTypeMappings[$linkType[MemberNames::CODE]][] = array(
888
                    $fullColumnName,
889
                    $callback,
890
                    $linkAttribute[MemberNames::PRODUCT_LINK_ATTRIBUTE_CODE]
891
                );
892
            }
893
        }
894
895
        // return the link type mappings
896
        return $linkTypeMappings;
897
    }
898
899
    /**
900
     * Returns the callback method used to extract the value of the passed
901
     * column to create the link type attribute value with.
902
     *
903
     * @param string $columnName The column name to create the callback for
904
     *
905
     * @return callable The callback
906
     */
907
    public function getLinkTypeColumnCallback($columnName)
908
    {
909
910
        // query whether or not a callback mapping is available
911
        if (isset($this->linkTypeAttributeColumnToCallbackMapping[$columnName])) {
912
            // load it from the array with the mappings
913
            list (, $callbackName) = $this->linkTypeAttributeColumnToCallbackMapping[$columnName];
914
            // prepare and return the callback
915
            return array($this, $callbackName);
916
        }
917
918
        // return the default callback
919
        return array($this, 'explode');
920
    }
921
922
    /**
923
     * Extracts the keys of the passed value by exploding them
924
     * with the also passed delimiter/value delmiter.
925
     *
926
     * @param string $value          The value to extract
927
     * @param string $delimiter      The delimiter used to extract the elements
928
     * @param string $valueDelimiter The delimiter used to extract the key from the value
929
     *
930
     * @return array The exploded keys
931
     */
932
    public function explodeKey($value, $delimiter = ',', $valueDelimiter = '=')
933
    {
934
935
        // initialize the array for the keys
936
        $keys = array();
937
938
        // extract the keys from the value
939
        foreach ($this->explode($value, $delimiter) as $keyValue) {
940
            // explode the key(s)
941
            $explodedKey = $this->explode($keyValue, $valueDelimiter);
942
            // extract the values of the exploded keys
943
            if (is_array($explodedKey)) {
944
                list ($keys[],) = $explodedKey;
945
            }
946
        }
947
948
        // return the array with the keys
949
        return $keys;
950
    }
951
952
    /**
953
     * Extracts the values of the passed value by exploding them
954
     * with the also passed delimiter/value delimiter.
955
     *
956
     * @param string $value          The value to extract
957
     * @param string $delimiter      The delimiter used to extract the elements
958
     * @param string $valueDelimiter The delimiter used to extract the key from the value
959
     *
960
     * @return array The exploded values
961
     */
962
    public function explodeValue($value, $delimiter = ',', $valueDelimiter = '=')
963
    {
964
965
        // initialize the array for the values
966
        $values = array();
967
968
        // extract the values from the value
969
        foreach ($this->explode($value, $delimiter) as $keyValue) {
970
            // explode the value(s)
971
            $explodedValue = $this->explode($keyValue, $valueDelimiter);
972
            // extract the values, whether or not two or less has been found
973
            if (is_array($explodedValue)) {
974
                if (count($explodedValue) < 2) {
975
                    $values[] = 0;
976
                } else {
977
                    list (, $values[]) = $explodedValue;
978
                }
979
            }
980
        }
981
982
        // return the array with the values
983
        return $values;
984
    }
985
}
986