Completed
Push — 19.x ( 3e6fd4...dbb391 )
by Tim
03:29
created

VariantSuperAttributeObserver::getParentId()   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 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Variant\Observers\VariantSuperAttributeObserver
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-variant
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Variant\Observers;
22
23
use TechDivision\Import\Utils\StoreViewCodes;
24
use TechDivision\Import\Observers\StateDetectorInterface;
25
use TechDivision\Import\Product\Utils\RelationTypes;
26
use TechDivision\Import\Product\Variant\Utils\ColumnKeys;
27
use TechDivision\Import\Product\Variant\Utils\MemberNames;
28
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
29
use TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface;
30
31
/**
32
 * Oberserver that provides functionality for the product variant super attributes replace operation.
33
 *
34
 * @author    Tim Wagner <[email protected]>
35
 * @copyright 2016 TechDivision GmbH <[email protected]>
36
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
37
 * @link      https://github.com/techdivision/import-product-variant
38
 * @link      http://www.techdivision.com
39
 */
40
class VariantSuperAttributeObserver extends AbstractProductImportObserver
41
{
42
43
    /**
44
     * The ID of the actual store to use.
45
     *
46
     * @var integer
47
     */
48
    protected $storeId;
49
50
    /**
51
     * The EAV attribute to handle.
52
     *
53
     * @var array
54
     */
55
    protected $eavAttribute;
56
57
    /**
58
     * The tempoarary stored product super attribute ID.
59
     *
60
     * @var integer
61
     */
62
    protected $productSuperAttributeId;
63
64
    /**
65
     * The product variant processor instance.
66
     *
67
     * @var \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface
68
     */
69
    protected $productVariantProcessor;
70
71
    /**
72
     * Initialize the observer with the passed product variant processor instance.
73
     *
74
     * @param \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface $productVariantProcessor The product variant processor instance
75
     * @param \TechDivision\Import\Observers\StateDetectorInterface                          $stateDetector           The state detector instance
76
     */
77
    public function __construct(ProductVariantProcessorInterface $productVariantProcessor, StateDetectorInterface $stateDetector = null)
78
    {
79
80
        // initialize the product variant processor instance
81
        $this->productVariantProcessor = $productVariantProcessor;
82
83
        // pass the state detector to the parent method
84
        parent::__construct($stateDetector);
85
    }
86
87
    /**
88
     * Return's the product variant processor instance.
89
     *
90
     * @return \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface The product variant processor instance
91
     */
92
    protected function getProductVariantProcessor()
93
    {
94
        return $this->productVariantProcessor;
95
    }
96
97
    /**
98
     * Process the observer's business logic.
99
     *
100
     * @return array The processed row
101
     */
102
    protected function process()
103
    {
104
105
        // extract the child SKU and attribute code from the row
106
        $parentSku = $this->getValue(ColumnKeys::VARIANT_PARENT_SKU);
107
        $attributeCode = $this->getValue(ColumnKeys::VARIANT_ATTRIBUTE_CODE);
108
109
        // query whether or not the super attribute has already been processed
110
        if ($this->hasBeenProcessedRelation($parentSku, $attributeCode, RelationTypes::VARIANT_SUPER_ATTRIBUTE)) {
111
            return;
112
        }
113
114
        // prepare the store view code
115
        $this->prepareStoreViewCode($this->getRow());
0 ignored issues
show
Unused Code introduced by
The call to VariantSuperAttributeObs...:prepareStoreViewCode() has too many arguments starting with $this->getRow().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
116
117
        // preserve the parent ID
118
        $this->setParentId($this->mapParentSku($parentSku));
119
120
        try {
121
            // load the EAV attribute with the found attribute code
122
            $this->setEavAttribute($this->getEavAttributeByAttributeCode($attributeCode));
123
        } catch (\Exception $e) {
124
            throw $this->wrapException(array(ColumnKeys::VARIANT_ATTRIBUTE_CODE), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...VARIANT_ATTRIBUTE_CODE) is of type array<integer,?>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
125
        }
126
127
        try {
128
            // initialize and save the super attribute
129
            if ($this->hasChanges($productSuperAttribute = $this->initializeProductSuperAttribute($this->prepareProducSuperAttributeAttributes()))) {
130
                $this->persistProductSuperAttribute($productSuperAttribute);
131
            }
132
133
            // initialize and save the super attribute label
134
            if ($this->hasChanges($productSuperAttributeLabel = $this->initializeProductSuperAttributeLabel($this->prepareProductSuperAttributeLabelAttributes()))) {
135
                $this->persistProductSuperAttributeLabel($productSuperAttributeLabel);
136
            }
137
138
            // mark the super attribute as processed
139
            $this->addProcessedRelation($parentSku, $attributeCode, RelationTypes::VARIANT_SUPER_ATTRIBUTE);
140
        } catch (\Exception $e) {
141
            // prepare a more detailed error message
142
            $message = $this->appendExceptionSuffix(
143
                sprintf(
144
                    'Super attribute for SKU %s and attribute %s can\'t be created',
145
                    $parentSku,
146
                    $attributeCode
147
                )
148
            );
149
150
            // if we're NOT in debug mode, re-throw a more detailed exception
151
            $wrappedException = $this->wrapException(
152
                array(ColumnKeys::VARIANT_PARENT_SKU, ColumnKeys::VARIANT_ATTRIBUTE_CODE),
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...VARIANT_ATTRIBUTE_CODE) is of type array<integer,?>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
153
                new \Exception($message, null, $e)
154
            );
155
156
            // query whether or not, debug mode is enabled
157
            if ($this->isDebugMode()) {
158
                // log a warning and return immediately
159
                $this->getSystemLogger()->warning($wrappedException->getMessage());
160
                return;
161
            }
162
163
            // else, throw the exception
164
            throw $wrappedException;
165
        }
166
    }
167
168
    /**
169
     * Prepare the product super attribute attributes that has to be persisted.
170
     *
171
     * @return array The prepared product attribute attributes
172
     */
173
    protected function prepareProducSuperAttributeAttributes()
174
    {
175
176
        // load the parent ID
177
        $parentId = $this->getParentId();
178
179
        // load the attribute ID
180
        $attributeId = $this->getAttributeId();
181
182
        // initialize the attributes and return them
183
        return $this->initializeEntity(
184
            array(
185
                MemberNames::PRODUCT_ID   => $parentId,
186
                MemberNames::ATTRIBUTE_ID => $attributeId,
187
                MemberNames::POSITION     => 0
188
            )
189
        );
190
    }
191
192
    /**
193
     * Prepare the product super attribute label attributes that has to be persisted.
194
     *
195
     * @return array The prepared product super attribute label attributes
196
     */
197
    protected function prepareProductSuperAttributeLabelAttributes()
198
    {
199
200
        // extract the parent/child ID as well as option value and variation label from the row
201
        $variationLabel = $this->getValue(ColumnKeys::VARIANT_VARIATION_LABEL);
202
203
        // query whether or not we've to create super attribute labels
204
        if (empty($variationLabel)) {
205
            $variationLabel = $this->getFrontendLabel();
206
        }
207
208
        // initialize the attributes and return them
209
        return $this->initializeEntity(
210
            array(
211
                MemberNames::PRODUCT_SUPER_ATTRIBUTE_ID => $this->getProductSuperAttributeId(),
212
                MemberNames::STORE_ID                   => $this->getRowStoreId(StoreViewCodes::ADMIN),
213
                MemberNames::USE_DEFAULT                => 0,
214
                MemberNames::VALUE                      => $variationLabel
215
            )
216
        );
217
    }
218
219
    /**
220
     * Initialize the product super attribute with the passed attributes and returns an instance.
221
     *
222
     * @param array $attr The product super attribute attributes
223
     *
224
     * @return array The initialized product super attribute
225
     */
226
    protected function initializeProductSuperAttribute(array $attr)
227
    {
228
        return $attr;
229
    }
230
231
    /**
232
     * Initialize the product super attribute label with the passed attributes and returns an instance.
233
     *
234
     * @param array $attr The product super attribute label attributes
235
     *
236
     * @return array The initialized product super attribute label
237
     */
238
    protected function initializeProductSuperAttributeLabel(array $attr)
239
    {
240
        return $attr;
241
    }
242
243
    /**
244
     * Set's the actual EAV attribute.
245
     *
246
     * @param array $eavAttribute The actual EAV attribute
247
     *
248
     * @return void
249
     */
250
    protected function setEavAttribute(array $eavAttribute)
251
    {
252
        $this->eavAttribute = $eavAttribute;
253
    }
254
255
    /**
256
     * Return's the actual EAV attribute.
257
     *
258
     * @return array The actual EAV attribute
259
     */
260
    protected function getEavAttribute()
261
    {
262
        return $this->eavAttribute;
263
    }
264
265
    /**
266
     * Return's the frontend label from the actual EAV attribute.
267
     *
268
     * @return string The frontend label
269
     */
270
    protected function getFrontendLabel()
271
    {
272
        return $this->eavAttribute[MemberNames::FRONTENT_LABEL];
273
    }
274
275
    /**
276
     * Return's the attribute ID from the actual EAV attribute.
277
     *
278
     * @return integer The attribute ID
279
     */
280
    protected function getAttributeId()
281
    {
282
        return $this->eavAttribute[MemberNames::ATTRIBUTE_ID];
283
    }
284
285
    /**
286
     * Set's the actual product super attribute ID.
287
     *
288
     * @param integer $productSuperAttributeId The product super attribute ID
289
     *
290
     * @return void
291
     */
292
    protected function setProductSuperAttributeId($productSuperAttributeId)
293
    {
294
        $this->productSuperAttributeId = $productSuperAttributeId;
295
    }
296
297
    /**
298
     * Return's the product super attribute ID.
299
     *
300
     * @return integer The product super attribute ID
301
     */
302
    protected function getProductSuperAttributeId()
303
    {
304
        return $this->productSuperAttributeId;
305
    }
306
307
    /**
308
     * Map's the passed SKU of the parent product to it's PK.
309
     *
310
     * @param string $parentSku The SKU of the parent product
311
     *
312
     * @return integer The primary key used to create relations
313
     */
314
    protected function mapParentSku($parentSku)
315
    {
316
        return $this->mapSkuToEntityId($parentSku);
317
    }
318
319
    /**
320
     * Return the entity ID for the passed SKU.
321
     *
322
     * @param string $sku The SKU to return the entity ID for
323
     *
324
     * @return integer The mapped entity ID
325
     * @throws \Exception Is thrown if the SKU is not mapped yet
326
     */
327
    protected function mapSkuToEntityId($sku)
328
    {
329
        return $this->getSubject()->mapSkuToEntityId($sku);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method mapSkuToEntityId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Prod...Subjects\VariantSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
330
    }
331
332
    /**
333
     * Set's the ID of the parent product to relate the variant with.
334
     *
335
     * @param integer $parentId The ID of the parent product
336
     *
337
     * @return void
338
     */
339
    protected function setParentId($parentId)
340
    {
341
        $this->getSubject()->setParentId($parentId);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method setParentId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...Subjects\VariantSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
342
    }
343
344
    /**
345
     * Return's the ID of the parent product to relate the variant with.
346
     *
347
     * @return integer The ID of the parent product
348
     */
349
    protected function getParentId()
350
    {
351
        return $this->getSubject()->getParentId();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method getParentId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...Subjects\VariantSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
352
    }
353
354
    /**
355
     * Return's the store for the passed store code.
356
     *
357
     * @param string $storeCode The store code to return the store for
358
     *
359
     * @return array The requested store
360
     * @throws \Exception Is thrown, if the requested store is not available
361
     */
362
    protected function getStoreByStoreCode($storeCode)
363
    {
364
        return $this->getSubject()->getStoreByStoreCode($storeCode);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method getStoreByStoreCode() does only exist in the following implementations of said interface: TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Prod...Subjects\VariantSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
365
    }
366
367
    /**
368
     * Return's an array with the available stores.
369
     *
370
     * @return array The available stores
371
     */
372
    protected function getStores()
373
    {
374
        return $this->getSubject()->getStores();
0 ignored issues
show
Bug introduced by
The method getStores() does not seem to exist on object<TechDivision\Impo...jects\SubjectInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
375
    }
376
377
    /**
378
     * Return's the first EAV attribute for the passed attribute code.
379
     *
380
     * @param string $attributeCode The attribute code
381
     *
382
     * @return array The array with the EAV attribute
383
     */
384
    protected function getEavAttributeByAttributeCode($attributeCode)
385
    {
386
        return $this->getSubject()->getEavAttributeByAttributeCode($attributeCode);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface TechDivision\Import\Subjects\SubjectInterface as the method getEavAttributeByAttributeCode() does only exist in the following implementations of said interface: TechDivision\Import\Observers\EntitySubjectImpl, TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Prod...Subjects\VariantSubject, TechDivision\Import\Subjects\AbstractEavSubject, TechDivision\Import\Subjects\ValidatorSubject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
387
    }
388
389
    /**
390
     * Persist's the passed product super attribute data and return's the ID.
391
     *
392
     * @param array $productSuperAttribute The product super attribute data to persist
393
     *
394
     * @return void
395
     */
396
    protected function persistProductSuperAttribute($productSuperAttribute)
397
    {
398
        $this->setProductSuperAttributeId($this->getProductVariantProcessor()->persistProductSuperAttribute($productSuperAttribute));
399
    }
400
401
    /**
402
     * Persist's the passed product super attribute label data and return's the ID.
403
     *
404
     * @param array $productSuperAttributeLabel The product super attribute label data to persist
405
     *
406
     * @return void
407
     */
408
    protected function persistProductSuperAttributeLabel($productSuperAttributeLabel)
409
    {
410
        return $this->getProductVariantProcessor()->persistProductSuperAttributeLabel($productSuperAttributeLabel);
411
    }
412
}
413