addArtefacts()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
ccs 0
cts 2
cp 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Converter\Product\Attribute\Observers\ProductToAttributeOptionValueConverterObserver
5
 *
6
 * PHP version 7
7
 *
8
 * @author    Tim Wagner <[email protected]>
9
 * @copyright 2019 TechDivision GmbH <[email protected]>
10
 * @license   https://opensource.org/licenses/MIT
11
 * @link      https://github.com/techdivision/import-converter-product-attribute
12
 * @link      http://www.techdivision.com
13
 */
14
15
namespace TechDivision\Import\Converter\Product\Attribute\Observers;
16
17
use TechDivision\Import\Utils\StoreViewCodes;
18
use TechDivision\Import\Utils\FrontendInputTypes;
19
use TechDivision\Import\Attribute\Utils\ColumnKeys;
20
use TechDivision\Import\Attribute\Utils\MemberNames;
21
use TechDivision\Import\Product\Utils\ConfigurationKeys;
22
use TechDivision\Import\Observers\StateDetectorInterface;
23
use TechDivision\Import\Services\ImportProcessorInterface;
24
use TechDivision\Import\Converter\Observers\AbstractConverterObserver;
25
use TechDivision\Import\Attribute\Callbacks\SwatchTypeLoaderInterface;
26
use TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface;
27
use TechDivision\Import\Observers\CleanUpEmptyColumnsTrait;
28
29
/**
30
 * Observer that extracts the missing attribute option values from a product CSV.
31
 *
32
 * @author    Tim Wagner <[email protected]>
33
 * @copyright 2019 TechDivision GmbH <[email protected]>
34
 * @license   https://opensource.org/licenses/MIT
35
 * @link      https://github.com/techdivision/import-converter-product-attribute
36
 * @link      http://www.techdivision.com
37
 */
38
class ProductToAttributeOptionValueConverterObserver extends AbstractConverterObserver
39
{
40
    use CleanUpEmptyColumnsTrait;
41
42
    /**
43
     * The artefact type.
44
     *
45
     * @var string
46
     */
47
    const ARTEFACT_TYPE = 'option-import';
48
49
    /**
50
     * The import processor instance.
51
     *
52
     * @var \TechDivision\Import\Services\ImportProcessorInterface
53
     */
54
    protected $importProcessor;
55
56
    /**
57
     * The attribute bunch processor instance.
58
     *
59
     * @var \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface
60
     */
61
    protected $attributeBunchProcessor;
62
63
    /**
64
     * The swatch type loader instance.
65
     *
66
     * @var \TechDivision\Import\Attribute\Callbacks\SwatchTypeLoaderInterface
67
     */
68
    protected $swatchTypeLoader;
69
70
    /**
71
     * Initialize the observer with the passed product bunch processor instance.
72
     *
73
     * @param \TechDivision\Import\Services\ImportProcessorInterface                   $importProcessor         The product bunch processor instance
74
     * @param \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface $attributeBunchProcessor The attribute bunch processor instance
75
     * @param \TechDivision\Import\Attribute\Callbacks\SwatchTypeLoaderInterface       $swatchTypeLoader        The swatch type loader instance
76
     * @param \TechDivision\Import\Observers\StateDetectorInterface|null               $stateDetector           The state detector instance to use
77
     */
78
    public function __construct(
79
        ImportProcessorInterface $importProcessor,
80
        AttributeBunchProcessorInterface $attributeBunchProcessor,
81
        SwatchTypeLoaderInterface $swatchTypeLoader,
82
        StateDetectorInterface $stateDetector = null
83
    ) {
84
85
        // initialize the swatch type loader and the processor instances
86
        $this->importProcessor = $importProcessor;
87
        $this->swatchTypeLoader = $swatchTypeLoader;
88
        $this->attributeBunchProcessor = $attributeBunchProcessor;
89
90
        // pass the state detector to the parent method
91
        parent::__construct($stateDetector);
92
    }
93
94
    /**
95
     * Process the observer's business logic.
96
     *
97
     * @return void
98
     */
99
    protected function process()
100
    {
101
102
        // initialize the store view code
103
        $this->prepareStoreViewCode();
104
105
        // load the store ID, use the admin store if NO store view code has been set
106
        $storeId = $this->getStoreId(StoreViewCodes::ADMIN);
107
108
        // load the user defined EAV attributes by the found attribute set and the backend types
109
        $attributes = $this->getEavUserDefinedAttributes();
110
111
        // load the header keys
112
        $headers = array_flip($this->getHeaders());
113
114
        // remove all the empty values from the row
115
        $row = $this->clearRow();
116
117
        // initialize the array for the artefacts
118
        $artefacts = array();
119
120
        // load the entity type ID
121
        $entityType = $this->loadEavEntityTypeByEntityTypeCode($this->getSubject()->getEntityTypeCode());
122
        $entityTypeId = $entityType[MemberNames::ENTITY_TYPE_ID];
123
124
        $emptyValueDefinition = $this->getEmptyAttributeValueConstant();
125
126
        // iterate over the attributes and append them to the row
127
        foreach ($row as $key => $attributeValue) {
128
            // query whether or not attribute with the found code exists
129
            if (!isset($attributes[$attributeCode = $headers[$key]])) {
130
                // log a message in debug mode
131
                if ($this->isDebugMode()) {
132
                    $this->getSystemLogger()->debug(
133
                        $this->appendExceptionSuffix(
134
                            sprintf(
135
                                'Can\'t find attribute with attribute code %s',
136
                                $attributeCode
137
                            )
138
                        )
139
                    );
140
                }
141
142
                // stop processing
143
                continue;
144
            } else {
145
                // log a message in debug mode
146
                if ($this->isDebugMode()) {
147
                    // log a message in debug mode
148
                    $this->getSystemLogger()->debug(
149
                        $this->appendExceptionSuffix(
150
                            sprintf(
151
                                'Found attribute with attribute code %s',
152
                                $attributeCode
153
                            )
154
                        )
155
                    );
156
                }
157
            }
158
159
            // if yes, load the attribute by its code
160
            $attribute = $attributes[$attributeCode];
161
162
            // we only support user defined EAV attributes of type select and multiselect
163
            if (in_array($attribute[MemberNames::FRONTEND_INPUT], array(FrontendInputTypes::SELECT, FrontendInputTypes::MULTISELECT))) {
164
                // explode the values if we've a multiselect
165
                $valuesExploded = $this->explode($attributeValue, $this->getMultipleValueDelimiter());
166
                // check if valueExploded an array to fix crash on next step "foreach"
167
                $values = is_array($valuesExploded) ? $valuesExploded : [];
168
                // iterate over the values
169
                foreach ($values as $value) {
170
                    // query whether the value corresponds to the Empty Value definition to skip
171
                    if ($value === $emptyValueDefinition) {
172
                        continue;
173
                    }
174
                    // query whether or not the attribute value already exists
175
                    if ($this->loadAttributeOptionValueByEntityTypeIdAndAttributeCodeAndStoreIdAndValue($entityTypeId, $attributeCode, $storeId, $value)) {
176
                        continue;
177
                    }
178
179
                    // try to load the swatch type, if available
180
                    $swatchType = $this->getSwatchTypeLoader()->loadSwatchType($entityTypeId, $attributeCode);
181
182
                    // add the artefact to the array
183
                    $artefacts[] = $this->newArtefact(
184
                        array(
185
                            ColumnKeys::DEFAULT_VALUE  => $attribute[MemberNames::DEFAULT_VALUE],
186
                            ColumnKeys::ATTRIBUTE_CODE => $attribute[MemberNames::ATTRIBUTE_CODE],
187
                            ColumnKeys::SORT_ORDER     => 0,
188
                            ColumnKeys::VALUE          => is_null($swatchType) ? $value : null,
189
                            ColumnKeys::SWATCH_TYPE    => $swatchType,
190
                            ColumnKeys::SWATCH_VALUE   => $swatchType ? $value : null
191
                        ),
192
                        array()
193
                    );
194
                }
195
            }
196
        }
197
198
        // export the array with artefacts
199
        $this->addArtefacts($artefacts);
200
    }
201
202
    /**
203
     * Returns the value(s) of the primary key column(s). As the primary key column can
204
     * also consist of two columns, the return value can be an array also.
205
     *
206
     * @return mixed The primary key value(s)
207
     */
208
    protected function getPrimaryKeyValue()
209
    {
210
        return $this->getValue(\TechDivision\Import\Product\Utils\ColumnKeys::SKU);
211
    }
212
213
    /**
214
     * Return's the import processor instance.
215
     *
216
     * @return \TechDivision\Import\Services\ImportProcessorInterface The import processor instance
217
     */
218
    protected function getImportProcessor()
219
    {
220
        return $this->importProcessor;
221
    }
222
223
    /**
224
     * Return's the attribute bunch processor instance.
225
     *
226
     * @return \TechDivision\Import\Attribute\Services\AttributeBunchProcessorInterface The attribute bunch processor instance
227
     */
228
    protected function getAttributeBunchProcessor()
229
    {
230
        return $this->attributeBunchProcessor;
231
    }
232
233
    /**
234
     * Return's the swatch type loader instance.
235
     *
236
     * @return \TechDivision\Import\Attribute\Callbacks\SwatchTypeLoaderInterface The swatch type loader instance
237
     */
238
    protected function getSwatchTypeLoader()
239
    {
240
        return $this->swatchTypeLoader;
241
    }
242
243
    /**
244
     * Return's an array with the available user defined EAV attributes for the actual entity type.
245
     *
246
     * @return array The array with the user defined EAV attributes
247
     */
248
    protected function getEavUserDefinedAttributes()
249
    {
250
        return $this->getSubject()->getEavUserDefinedAttributes();
251
    }
252
253
    /**
254
     * Return's an EAV entity type with the passed entity type code.
255
     *
256
     * @param string $entityTypeCode The code of the entity type to return
257
     *
258
     * @return array The entity type with the passed entity type code
259
     */
260
    protected function loadEavEntityTypeByEntityTypeCode($entityTypeCode)
261
    {
262
        return $this->getImportProcessor()->getEavEntityTypeByEntityTypeCode($entityTypeCode);
263
    }
264
265
    /**
266
     * Load's and return's the EAV attribute option value with the passed entity type ID, code, store ID and value.
267
     *
268
     * @param string  $entityTypeId  The entity type ID of the EAV attribute to load the option value for
269
     * @param string  $attributeCode The code of the EAV attribute option to load
270
     * @param integer $storeId       The store ID of the attribute option to load
271
     * @param string  $value         The value of the attribute option to load
272
     *
273
     * @return array The EAV attribute option value
274
     */
275
    protected function loadAttributeOptionValueByEntityTypeIdAndAttributeCodeAndStoreIdAndValue($entityTypeId, $attributeCode, $storeId, $value)
276
    {
277
        return $this->getAttributeBunchProcessor()->loadAttributeOptionValueByEntityTypeIdAndAttributeCodeAndStoreIdAndValue($entityTypeId, $attributeCode, $storeId, $value);
278
    }
279
280
    /**
281
     * Create's and return's a new empty artefact entity.
282
     *
283
     * @param array $columns             The array with the column data
284
     * @param array $originalColumnNames The array with a mapping from the old to the new column names
285
     *
286
     * @return array The new artefact entity
287
     */
288
    protected function newArtefact(array $columns, array $originalColumnNames)
289
    {
290
        return $this->getSubject()->newArtefact($columns, $originalColumnNames);
291
    }
292
293
    /**
294
     * Add the passed product type artefacts to the product with the
295
     * last entity ID.
296
     *
297
     * @param array $artefacts The product type artefacts
298
     *
299
     * @return void
300
     * @uses \TechDivision\Import\Product\Media\Subjects\MediaSubject::getLastEntityId()
301
     */
302
    protected function addArtefacts(array $artefacts)
303
    {
304
        $this->getSubject()->addArtefacts(ProductToAttributeOptionValueConverterObserver::ARTEFACT_TYPE, $artefacts);
305
    }
306
}
307