Completed
Push — 23.x ( e092bd )
by Tim
05:28
created

BunchSubject   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 335
Duplicated Lines 8.66 %

Coupling/Cohesion

Components 2
Dependencies 8

Test Coverage

Coverage 35%

Importance

Changes 0
Metric Value
wmc 22
lcom 2
cbo 8
dl 29
loc 335
ccs 21
cts 60
cp 0.35
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 1
B setUp() 14 42 7
A tearDown() 0 17 1
A getDefaultCallbackMappings() 0 4 1
A getHeaderStockMappings() 0 4 1
A getVisibilityIdByValue() 0 16 2
A preLoadEntityId() 0 4 1
A getEntityType() 15 15 2
A isUrlKeyOf() 0 5 2
A getMediaRoles() 0 4 1
A getCleanUpColumns() 0 14 2
A getEntityTypeCode() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Subjects\BunchSubject
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 Doctrine\Common\Collections\Collection;
24
use League\Event\EmitterInterface;
25
use TechDivision\Import\Loaders\LoaderInterface;
26
use TechDivision\Import\Services\RegistryProcessorInterface;
27
use TechDivision\Import\Utils\Generators\GeneratorInterface;
28
use TechDivision\Import\Utils\StoreViewCodes;
29
use TechDivision\Import\Utils\Mappings\MapperInterface;
30
use TechDivision\Import\Product\Utils\MemberNames;
31
use TechDivision\Import\Product\Utils\RegistryKeys;
32
use TechDivision\Import\Product\Utils\VisibilityKeys;
33
use TechDivision\Import\Product\Utils\ConfigurationKeys;
34
use TechDivision\Import\Subjects\ExportableTrait;
35
use TechDivision\Import\Subjects\FileUploadTrait;
36
use TechDivision\Import\Subjects\ExportableSubjectInterface;
37
use TechDivision\Import\Subjects\FileUploadSubjectInterface;
38
use TechDivision\Import\Subjects\UrlKeyAwareSubjectInterface;
39
use TechDivision\Import\Subjects\CleanUpColumnsSubjectInterface;
40
41
/**
42
 * The subject implementation that handles the business logic to persist products.
43
 *
44
 * @author    Tim Wagner <[email protected]>
45
 * @copyright 2016 TechDivision GmbH <[email protected]>
46
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
47
 * @link      https://github.com/techdivision/import-product
48
 * @link      http://www.techdivision.com
49
 */
50
class BunchSubject extends AbstractProductSubject implements ExportableSubjectInterface, FileUploadSubjectInterface, UrlKeyAwareSubjectInterface, CleanUpColumnsSubjectInterface
51
{
52
53
    /**
54
     * The trait that implements the export functionality.
55
     *
56
     * @var \TechDivision\Import\Subjects\ExportableTrait
57
     */
58
    use ExportableTrait;
59
60
    /**
61
     * The trait that provides file upload functionality.
62
     *
63
     * @var \TechDivision\Import\Subjects\FileUploadTrait
64
     */
65
    use FileUploadTrait;
66
67
    /**
68
     * The array with the pre-loaded entity IDs.
69
     *
70
     * @var array
71
     */
72
    protected $preLoadedEntityIds = array();
73
74
    /**
75
     * Mappings for the table column => CSV column header.
76
     *
77
     * @var array
78
     */
79
    protected $headerStockMappings = array(
80
        'qty'                         => array('qty', 'float'),
81
        'min_qty'                     => array('out_of_stock_qty', 'float'),
82
        'use_config_min_qty'          => array('use_config_min_qty', 'int'),
83
        'is_qty_decimal'              => array('is_qty_decimal', 'int'),
84
        'backorders'                  => array('allow_backorders', 'int'),
85
        'use_config_backorders'       => array('use_config_backorders', 'int'),
86
        'min_sale_qty'                => array('min_cart_qty', 'float'),
87
        'use_config_min_sale_qty'     => array('use_config_min_sale_qty', 'int'),
88
        'max_sale_qty'                => array('max_cart_qty', 'float'),
89
        'use_config_max_sale_qty'     => array('use_config_max_sale_qty', 'int'),
90
        'is_in_stock'                 => array('is_in_stock', 'int'),
91
        'notify_stock_qty'            => array('notify_on_stock_below', 'float'),
92
        'use_config_notify_stock_qty' => array('use_config_notify_stock_qty', 'int'),
93
        'manage_stock'                => array('manage_stock', 'int'),
94
        'use_config_manage_stock'     => array('use_config_manage_stock', 'int'),
95
        'use_config_qty_increments'   => array('use_config_qty_increments', 'int'),
96
        'qty_increments'              => array('qty_increments', 'float'),
97
        'use_config_enable_qty_inc'   => array('use_config_enable_qty_inc', 'int'),
98
        'enable_qty_increments'       => array('enable_qty_increments', 'int'),
99
        'is_decimal_divided'          => array('is_decimal_divided', 'int'),
100
    );
101
102
    /**
103
     * The array with the available visibility keys.
104
     *
105
     * @var array
106
     */
107
    protected $availableVisibilities = array(
108
        'Not Visible Individually' => VisibilityKeys::VISIBILITY_NOT_VISIBLE,
109
        'Catalog'                  => VisibilityKeys::VISIBILITY_IN_CATALOG,
110
        'Search'                   => VisibilityKeys::VISIBILITY_IN_SEARCH,
111
        'Catalog, Search'          => VisibilityKeys::VISIBILITY_BOTH
112
    );
113
114
    /**
115
     * The default callback mappings for the Magento standard product attributes.
116
     *
117
     * @var array
118
     */
119
    protected $defaultCallbackMappings = array(
120
        'visibility'           => array('import_product.callback.visibility'),
121
        'tax_class_id'         => array('import_product.callback.tax.class'),
122
        'bundle_price_type'    => array('import_product_bundle.callback.bundle.type'),
123
        'bundle_sku_type'      => array('import_product_bundle.callback.bundle.type'),
124
        'bundle_weight_type'   => array('import_product_bundle.callback.bundle.type'),
125
        'bundle_price_view'    => array('import_product_bundle.callback.bundle.price.view'),
126
        'bundle_shipment_type' => array('import_product_bundle.callback.bundle.shipment.type')
127
    );
128
129
    /**
130
     * The available entity types.
131
     *
132
     * @var array
133
     */
134
    protected $entityTypes = array();
135
136
    /**
137
     * The media roles loader instance.
138
     *
139
     * @var \TechDivision\Import\Loaders\LoaderInterface
140
     */
141
    protected $mediaRolesLoader;
142
143
    /**
144
     * The entity type code mapper instance.
145
     *
146
     * @var \TechDivision\Import\Utils\Mappings\MapperInterface
147
     */
148
    protected $entityTypeCodeMapper;
149
150
    /**
151
     * BunchSubject constructor
152
     *
153
     * @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor          The registry processor instance
154
     * @param \TechDivision\Import\Utils\Generators\GeneratorInterface $coreConfigDataUidGenerator The UID generator for the core config data
155
     * @param \Doctrine\Common\Collections\Collection                  $systemLoggers              The array with the system loggers instances
156
     * @param \League\Event\EmitterInterface                           $emitter                    The event emitter instance
157
     * @param \TechDivision\Import\Loaders\LoaderInterface             $mediaRolesLoader           The media type loader instance
158
     * @param \TechDivision\Import\Utils\Mappings\MapperInterface      $entityTypeCodeMapper       The entity type code mapper instance
159
     */
160 18
    public function __construct(
161
        RegistryProcessorInterface $registryProcessor,
162
        GeneratorInterface $coreConfigDataUidGenerator,
163
        Collection $systemLoggers,
164
        EmitterInterface $emitter,
165
        LoaderInterface $mediaRolesLoader,
166
        MapperInterface $entityTypeCodeMapper
167
    ) {
168
169
        // set the loader for the media roles and the entity type code mapper
170 18
        $this->mediaRolesLoader = $mediaRolesLoader;
171 18
        $this->entityTypeCodeMapper = $entityTypeCodeMapper;
172
173
        // pass the other instances to the parent constructor
174 18
        parent::__construct($registryProcessor, $coreConfigDataUidGenerator, $systemLoggers, $emitter);
175 18
    }
176
177
    /**
178
     * Intializes the previously loaded global data for exactly one bunch.
179
     *
180
     * @param string $serial The serial of the actual import
181
     *
182
     * @return void
183
     */
184 18
    public function setUp($serial)
185
    {
186
187
        // load the status of the actual import
188 18
        $status = $this->getRegistryProcessor()->getAttribute(RegistryKeys::STATUS);
189
190
        // load the global data we've prepared initially
191 18
        $this->entityTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::ENTITY_TYPES];
192
193
        // initialize the flag whether to copy images or not
194 18
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::COPY_IMAGES)) {
195
            $this->setCopyImages($this->getConfiguration()->getParam(ConfigurationKeys::COPY_IMAGES));
0 ignored issues
show
Documentation introduced by
$this->getConfiguration(...ationKeys::COPY_IMAGES) is of type string, but the function expects a boolean.

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...
196
        }
197
198
        // initialize the flag whether to override images or not
199
        // @todo https://github.com/techdivision/import/issues/181
200
        //       Create new constant ConfigurationKeys::OVERRIDE_IMAGES for future release
201 18
        if ($this->getConfiguration()->hasParam('override-images')) {
202
            $this->setOverrideImages($this->getConfiguration()->getParam('override-images'));
0 ignored issues
show
Documentation introduced by
$this->getConfiguration(...aram('override-images') is of type string, but the function expects a boolean.

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...
203
        }
204
205
        // initialize media directory => can be absolute or relative
206 18 View Code Duplication
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::MEDIA_DIRECTORY)) {
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...
207
            try {
208
                $this->setMediaDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::MEDIA_DIRECTORY)));
209
            } catch (\InvalidArgumentException $iae) {
210
                $this->getSystemLogger()->warning($iae->getMessage());
211
            }
212
        }
213
214
        // initialize images directory => can be absolute or relative
215 18 View Code Duplication
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::IMAGES_FILE_DIRECTORY)) {
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...
216
            try {
217
                $this->setImagesFileDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::IMAGES_FILE_DIRECTORY)));
218
            } catch (\InvalidArgumentException $iae) {
219
                $this->getSystemLogger()->warning($iae->getMessage());
220
            }
221
        }
222
223
        // invoke the parent method
224 18
        parent::setUp($serial);
225 18
    }
226
227
    /**
228
     * Clean up the global data after importing the bunch.
229
     *
230
     * @param string $serial The serial of the actual import
231
     *
232
     * @return void
233
     */
234
    public function tearDown($serial)
235
    {
236
237
        // invoke the parent method
238
        parent::tearDown($serial);
239
240
        // load the registry processor
241
        $registryProcessor = $this->getRegistryProcessor();
242
243
        // update the status
244
        $registryProcessor->mergeAttributesRecursive(
245
            RegistryKeys::STATUS,
246
            array(
247
                RegistryKeys::PRE_LOADED_ENTITY_IDS => $this->preLoadedEntityIds,
248
            )
249
        );
250
    }
251
252
    /**
253
     * Return's the default callback mappings.
254
     *
255
     * @return array The default callback mappings
256
     */
257
    public function getDefaultCallbackMappings()
258
    {
259
        return $this->defaultCallbackMappings;
260
    }
261
262
    /**
263
     * Return's the mappings for the table column => CSV column header.
264
     *
265
     * @return array The header stock mappings
266
     */
267 1
    public function getHeaderStockMappings()
268
    {
269 1
        return $this->headerStockMappings;
270
    }
271
272
    /**
273
     * Return's the visibility key for the passed visibility string.
274
     *
275
     * @param string $visibility The visibility string to return the key for
276
     *
277
     * @return integer The requested visibility key
278
     * @throws \Exception Is thrown, if the requested visibility is not available
279
     */
280
    public function getVisibilityIdByValue($visibility)
281
    {
282
283
        // query whether or not, the requested visibility is available
284
        if (isset($this->availableVisibilities[$visibility])) {
285
            // load the visibility ID, add the mapping and return the ID
286
            return $this->availableVisibilities[$visibility];
287
        }
288
289
        // throw an exception, if not
290
        throw new \Exception(
291
            $this->appendExceptionSuffix(
292
                sprintf('Found invalid visibility %s', $visibility)
293
            )
294
        );
295
    }
296
297
    /**
298
     * Pre-load the entity ID for the passed product.
299
     *
300
     * @param array $product The product to be pre-loaded
301
     *
302
     * @return void
303
     */
304
    public function preLoadEntityId(array $product)
305
    {
306
        $this->preLoadedEntityIds[$product[MemberNames::SKU]] = $product[MemberNames::ENTITY_ID];
307
    }
308
309
    /**
310
     * Return's the entity type for the configured entity type code.
311
     *
312
     * @return array The requested entity type
313
     * @throws \Exception Is thrown, if the requested entity type is not available
314
     */
315 1 View Code Duplication
    public function getEntityType()
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...
316
    {
317
318
        // query whether or not the entity type with the passed code is available
319 1
        if (isset($this->entityTypes[$entityTypeCode = $this->getEntityTypeCode()])) {
320 1
            return $this->entityTypes[$entityTypeCode];
321
        }
322
323
        // throw a new exception
324
        throw new \Exception(
325
            $this->appendExceptionSuffix(
326
                sprintf('Requested entity type "%s" is not available', $entityTypeCode)
327
            )
328
        );
329
    }
330
331
    /**
332
     * Return's TRUE, if the passed URL key varchar value IS related with the actual PK.
333
     *
334
     * @param array $productVarcharAttribute The varchar value to check
335
     *
336
     * @return boolean TRUE if the URL key is related, else FALSE
337
     */
338
    public function isUrlKeyOf(array $productVarcharAttribute)
339
    {
340
        return ((integer) $productVarcharAttribute[MemberNames::ENTITY_ID] === (integer) $this->getLastEntityId()) &&
341
               ((integer) $productVarcharAttribute[MemberNames::STORE_ID] === (integer) $this->getRowStoreId(StoreViewCodes::ADMIN));
342
    }
343
344
    /**
345
     * Loads and returns the media roles.
346
     *
347
     * @return array The array with the media roles
348
     */
349
    public function getMediaRoles(): array
350
    {
351
        return $this->mediaRolesLoader->load();
352
    }
353
354
    /**
355
     * Merge the columns from the configuration with all image type columns to define which
356
     * columns should be cleaned-up.
357
     *
358
     * @return array The columns that has to be cleaned-up
359
     */
360
    public function getCleanUpColumns()
361
    {
362
363
        // initialize the array for the columns that has to be cleaned-up
364
        $cleanUpColumns = array();
365
366
        // query whether or not an array has been specified in the configuration
367
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS)) {
368
            $cleanUpColumns = $this->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_EMPTY_COLUMNS);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->getConfiguration(...LEAN_UP_EMPTY_COLUMNS); of type string adds the type string to the return on line 372 which is incompatible with the return type declared by the interface TechDivision\Import\Subj...face::getCleanUpColumns of type array.
Loading history...
369
        }
370
371
        // return the array with the column names
372
        return $cleanUpColumns;
373
    }
374
375
    /**
376
     * Return's the entity type code to be used.
377
     *
378
     * @return string The entity type code to be used
379
     */
380 18
    public function getEntityTypeCode()
381
    {
382 18
        return $this->entityTypeCodeMapper->map(parent::getEntityTypeCode());
383
    }
384
}
385