Passed
Push — master ( 9cd536...6f4cb8 )
by Tim
03:48
created

AdditionalAttributeCsvSerializer::denormalize()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 20
rs 10
cc 3
nc 2
nop 1
1
<?php
2
3
/**
4
 * TechDivision\Import\Serializers\AdditionalAttributeCsvSerializer
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 2021 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-serializer-csv
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Serializer\Csv;
22
23
use TechDivision\Import\Serializer\SerializerInterface;
24
use TechDivision\Import\Serializer\SerializerFactoryInterface;
25
use TechDivision\Import\Serializer\Configuration\ConfigurationInterface;
26
use TechDivision\Import\Serializer\Configuration\SerializerConfigurationInterface;
27
use TechDivision\Import\Serializer\Csv\Utils\MemberNames;
28
use TechDivision\Import\Serializer\Csv\Utils\FrontendInputTypes;
29
use TechDivision\Import\Serializer\Csv\Services\EavAttributeAwareProcessorInterface;
30
31
/**
32
 * Serializer implementation that un-/serializes the additional product attribues found in the CSV file
33
 * in the row 'additional_attributes'.
34
 *
35
 * @author    Tim Wagner <[email protected]>
36
 * @copyright 2021 TechDivision GmbH <[email protected]>
37
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
38
 * @link      https://github.com/techdivision/import-serializer-csv
39
 * @link      http://www.techdivision.com
40
 */
41
class AdditionalAttributeCsvSerializer extends AbstractCsvSerializer
42
{
43
44
    /**
45
     * The factory instance for the CSV value serializer.
46
     *
47
     * @var \TechDivision\Import\Serializer\SerializerFactoryInterface
48
     */
49
    private $valueCsvSerializerFactory;
50
51
    /**
52
     * The CSV value serializer instance.
53
     *
54
     * @var \TechDivision\Import\Serializer\SerializerInterface
55
     */
56
    private $valueCsvSerializer;
57
58
    /**
59
     * The entity type from the configuration.
60
     *
61
     * @var array
62
     */
63
    private $entityType = array();
64
65
    /**
66
     *  The configuration instance.
67
     *
68
     * @var \TechDivision\Import\Serializer\Configuration\ConfigurationInterface
69
     */
70
    private $configuration;
71
72
    /**
73
     * The attribute loader instance.
74
     *
75
     * @var \TechDivision\Import\Serializer\Csv\Services\EavAttributeAwareProcessorInterface
76
     */
77
    private $eavAttributeAwareProcessor;
78
79
    /**
80
     * Initialize the serializer with the passed CSV value serializer factory.
81
     *
82
     * @param \TechDivision\Import\Serializer\Configuration\ConfigurationInterface             $configuration             The configuration instance
83
     * @param \TechDivision\Import\Serializer\Csv\Services\EavAttributeAwareProcessorInterface $attributeLoader           The attribute loader instance
84
     * @param \TechDivision\Import\Serializer\SerializerFactoryInterface                       $valueCsvSerializerFactory The CSV value serializer factory
85
     */
86
    public function __construct(
87
        ConfigurationInterface $configuration,
88
        EavAttributeAwareProcessorInterface $attributeLoader,
89
        SerializerFactoryInterface $valueCsvSerializerFactory
90
    ) {
91
92
        // set the passed instances
93
        $this->configuration = $configuration;
94
        $this->eavAttributeAwareProcessor = $attributeLoader;
95
        $this->valueCsvSerializerFactory = $valueCsvSerializerFactory;
96
97
        // load the entity type for the entity type defined in the configuration
98
        $this->entityType = $attributeLoader->getEavEntityTypeByEntityTypeCode($configuration->getEntityTypeCode());
99
    }
100
101
    /**
102
     * Returns the configuration instance.
103
     *
104
     * @return \TechDivision\Import\Serializer\Configuration\ConfigurationInterface The configuration instance
105
     */
106
    protected function getConfiguration()
107
    {
108
        return $this->configuration;
109
    }
110
111
    /**
112
     * Returns the factory instance for the CSV value serializer.
113
     *
114
     * @return \TechDivision\Import\Serializer\SerializerFactoryInterface The CSV value serializer factory instance
115
     */
116
    protected function getValueCsvSerializerFactory()
117
    {
118
        return $this->valueCsvSerializerFactory;
119
    }
120
121
    /**
122
     * Returns the CSV value serializer instance.
123
     *
124
     * @param \TechDivision\Import\Serializer\SerializerInterface $valueCsvSerializer The CSV value serializer instance
125
     *
126
     * @return void
127
     */
128
    protected function setValueCsvSerializer(SerializerInterface $valueCsvSerializer)
129
    {
130
        $this->valueCsvSerializer = $valueCsvSerializer;
131
    }
132
133
    /**
134
     * Returns the CSV value serializer instance.
135
     *
136
     * @return \TechDivision\Import\Serializer\SerializerInterface The CSV value serializer instance
137
     */
138
    protected function getValueCsvSerializer()
139
    {
140
        return $this->valueCsvSerializer;
141
    }
142
143
    /**
144
     * Returns the EAV attribute aware processor instance.
145
     *
146
     * @return \TechDivision\Import\Serializer\Csv\Services\EavAttributeAwareProcessorInterface The EAV attribute aware processor instance
147
     */
148
    protected function getEavAttributeAwareProcessor() : EavAttributeAwareProcessorInterface
149
    {
150
        return $this->eavAttributeAwareProcessor;
151
    }
152
153
    /**
154
     * Returns entity type ID mapped from the configuration.
155
     *
156
     * @return integer The mapped entity type ID
157
     */
158
    protected function getEntityTypeId()
159
    {
160
        return $this->entityType[MemberNames::ENTITY_TYPE_ID];
161
    }
162
163
    /**
164
     * Returns the multiple value delimiter from the configuration.
165
     *
166
     * @return string The multiple value delimiter
167
     */
168
    protected function getMultipleValueDelimiter()
169
    {
170
        return $this->getConfiguration()->getMultipleValueDelimiter();
171
    }
172
173
    /**
174
     * Returns the multiple field delimiter from the configuration.
175
     *
176
     * @return string The multiple field delimiter
177
     */
178
    protected function getMultipleFieldDelimiter()
179
    {
180
        return $this->getConfiguration()->getMultipleFieldDelimiter();
181
    }
182
183
    /**
184
     * Loads and returns the attribute with the passed code from the database.
185
     *
186
     * @param string $attributeCode The code of the attribute to return
187
     *
188
     * @return array The attribute
189
     */
190
    protected function loadAttributeByAttributeCode($attributeCode)
191
    {
192
        return $this->getEavAttributeAwareProcessor()->getEavAttributeByEntityTypeIdAndAttributeCode($this->getEntityTypeId(), $attributeCode);
193
    }
194
195
    /**
196
     * Packs the passed value according to the frontend input type of the attribute with the passed code.
197
     *
198
     * @param string $attributeCode The code of the attribute to pack the passed value for
199
     * @param mixed  $value         The value to pack
200
     *
201
     * @return string The packed value
202
     */
203
    protected function pack($attributeCode, $value)
204
    {
205
206
        // load the attibute with the passed code
207
        $attribute = $this->loadAttributeByAttributeCode($attributeCode);
208
209
        // pack the value according to the attribute's frontend input type
210
        switch ($attribute[MemberNames::FRONTEND_INPUT]) {
211
            case FrontendInputTypes::MULTISELECT:
212
                return implode($this->getMultipleValueDelimiter(), $value);
213
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
214
215
            case FrontendInputTypes::BOOLEAN:
216
                return $value === true ? 'true' : 'false';
217
                break;
218
219
            default:
220
                return $value;
221
        }
222
    }
223
224
    /**
225
     * Unpacks the passed value according to the frontend input type of the attribute with the passed code.
226
     *
227
     * @param string $attributeCode The code of the attribute to pack the passed value for
228
     * @param string $value         The value to unpack
229
     *
230
     * @return mixed The unpacked value
231
     */
232
    protected function unpack($attributeCode, $value)
233
    {
234
235
        // load the attibute with the passed code
236
        $attribute = $this->loadAttributeByAttributeCode($attributeCode);
237
238
        // unpack the value according to the attribute's frontend input type
239
        switch ($attribute[MemberNames::FRONTEND_INPUT]) {
240
            case FrontendInputTypes::MULTISELECT:
241
                return explode($this->getMultipleValueDelimiter(), $value);
242
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
243
244
            case FrontendInputTypes::BOOLEAN:
245
                return filter_var($value, FILTER_VALIDATE_BOOLEAN);
246
                break;
247
248
            default:
249
                return $value;
250
        }
251
    }
252
253
    /**
254
     * Passes the configuration and initializes the serializer.
255
     *
256
     * @param \TechDivision\Import\Serializer\Configuration\SerializerConfigurationInterface $configuration The CSV configuration
257
     *
258
     * @return void
259
     */
260
    public function init(SerializerConfigurationInterface $configuration)
261
    {
262
263
        // pass the configuration to the parent instance
264
        parent::init($configuration);
265
266
        // create the CSV value serializer instance
267
        $this->setValueCsvSerializer($this->getValueCsvSerializerFactory()->createSerializer($configuration));
268
    }
269
270
    /**
271
     * Unserializes the elements of the passed string.
272
     *
273
     * @param string|null $serialized The value to unserialize
274
     * @param string|null $delimiter  The delimiter used to unserialize the elements
275
     *
276
     * @return array The unserialized values
277
     * @see \TechDivision\Import\Serializer\SerializerInterface::unserialize()
278
     */
279
    public function unserialize($serialized = null, $delimiter = null)
280
    {
281
        return $this->getValueCsvSerializer()->explode($serialized, $delimiter ? $delimiter : $this->getMultipleFieldDelimiter());
282
    }
283
284
    /**
285
     * Serializes the elements of the passed array.
286
     *
287
     * @param array|null  $unserialized The serialized data
288
     * @param string|null $delimiter    The delimiter used to serialize the values
289
     *
290
     * @return string The serialized array
291
     * @see \TechDivision\Import\Serializer\SerializerInterface::serialize()
292
     */
293
    public function serialize(array $unserialized = null, $delimiter = null)
294
    {
295
        return $this->getValueCsvSerializer()->implode($unserialized, $delimiter ? $delimiter : $this->getMultipleFieldDelimiter());
296
    }
297
298
    /**
299
     * Extracts the elements of the passed value by exploding them
300
     * with the also passed delimiter.
301
     *
302
     * @param string|null $value     The value to extract
303
     * @param string|null $delimiter The delimiter used to extrace the elements
304
     *
305
     * @return array|null The exploded values
306
     * @see \TechDivision\Import\Serializer\SerializerInterface::unserialize()
307
     */
308
    public function explode($value = null, $delimiter = null)
309
    {
310
        return $this->unserialize($value, $delimiter);
311
    }
312
313
    /**
314
     * Compacts the elements of the passed value by imploding them
315
     * with the also passed delimiter.
316
     *
317
     * @param array|null  $value     The values to compact
318
     * @param string|null $delimiter The delimiter use to implode the values
319
     *
320
     * @return string|null The compatected value
321
     * @see \TechDivision\Import\Serializer\SerializerInterface::serialize()
322
     */
323
    public function implode(array $value = null, $delimiter = null)
324
    {
325
        return $this->serialize($value, $delimiter);
326
    }
327
328
    /**
329
     * Create a CSV compatible string from the passed category path.
330
     *
331
     * @param string|null $value The normalized category path (usually from the DB)
332
     *
333
     * @return array The array with the denormalized attribute values
334
     */
335
    public function denormalize(string $value = null) : array
336
    {
337
338
        // initialize the array for the attributes
339
        $attrs = array();
340
341
        // explode the additional attributes
342
        $additionalAttributes = $this->unserialize($value);
343
344
        // iterate over the attributes and append them to the row
345
        if (is_array($additionalAttributes)) {
0 ignored issues
show
introduced by
The condition is_array($additionalAttributes) is always true.
Loading history...
346
            foreach ($additionalAttributes as $additionalAttribute) {
347
                // explode attribute code/option value from the attribute
348
                list ($attributeCode, $optionValue) = $this->explode($additionalAttribute, '=');
349
                $attrs[$attributeCode] = $this->unpack($attributeCode, $optionValue);
350
            }
351
        }
352
353
        // return the extracted array with the additional attributes
354
        return $attrs;
355
    }
356
357
    /**
358
     * Normalizes the category path in a standard representation.
359
     *
360
     * For example this means, that a category  path `Default Category/Gear`
361
     * will be normalized into `"Default Category"/Gear`.
362
     *
363
     * @param array $values The category path that has to be normalized
364
     *
365
     * @return string The normalized category path
366
     */
367
    public function normalize(array $values) : string
368
    {
369
370
        // initialize the array for the attributes
371
        $attrs = array();
372
373
        // iterate over the attributes and append them to the row
374
        if (is_array($values)) {
0 ignored issues
show
introduced by
The condition is_array($values) is always true.
Loading history...
375
            foreach ($values as $attributeCode => $optionValue) {
376
                $attrs[] = sprintf('%s=%s', $attributeCode, $this->pack($attributeCode, $optionValue));
377
            }
378
        }
379
380
        // implode the array with the packed additional attributes and return it
381
        return $this->serialize($attrs);
382
    }
383
}
384