Completed
Pull Request — master (#162)
by Tim
19:46 queued 09:36
created

BunchSubject::isUrlKeyOf()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
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\Mappings\MapperInterface;
29
use TechDivision\Import\Product\Utils\MemberNames;
30
use TechDivision\Import\Product\Utils\RegistryKeys;
31
use TechDivision\Import\Product\Utils\VisibilityKeys;
32
use TechDivision\Import\Product\Utils\ConfigurationKeys;
33
use TechDivision\Import\Subjects\ExportableTrait;
34
use TechDivision\Import\Subjects\FileUploadTrait;
35
use TechDivision\Import\Subjects\ExportableSubjectInterface;
36
use TechDivision\Import\Subjects\FileUploadSubjectInterface;
37
use TechDivision\Import\Subjects\UrlKeyAwareSubjectInterface;
38
use TechDivision\Import\Subjects\CleanUpColumnsSubjectInterface;
39
40
/**
41
 * The subject implementation that handles the business logic to persist products.
42
 *
43
 * @author    Tim Wagner <[email protected]>
44
 * @copyright 2016 TechDivision GmbH <[email protected]>
45
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
46
 * @link      https://github.com/techdivision/import-product
47
 * @link      http://www.techdivision.com
48
 */
49
class BunchSubject extends AbstractProductSubject implements ExportableSubjectInterface, FileUploadSubjectInterface, UrlKeyAwareSubjectInterface, CleanUpColumnsSubjectInterface
50
{
51
52
    /**
53
     * The trait that implements the export functionality.
54
     *
55
     * @var \TechDivision\Import\Subjects\ExportableTrait
56
     */
57
    use ExportableTrait;
58
59
    /**
60
     * The trait that provides file upload functionality.
61
     *
62
     * @var \TechDivision\Import\Subjects\FileUploadTrait
63
     */
64
    use FileUploadTrait;
65
66
    /**
67
     * The array with the pre-loaded entity IDs.
68
     *
69
     * @var array
70
     */
71
    protected $preLoadedEntityIds = array();
72
73
    /**
74
     * Mappings for the table column => CSV column header.
75
     *
76
     * @var array
77
     */
78
    protected $headerStockMappings = array(
79
        'qty'                         => array('qty', 'float'),
80
        'min_qty'                     => array('out_of_stock_qty', 'float'),
81
        'use_config_min_qty'          => array('use_config_min_qty', 'int'),
82
        'is_qty_decimal'              => array('is_qty_decimal', 'int'),
83
        'backorders'                  => array('allow_backorders', 'int'),
84
        'use_config_backorders'       => array('use_config_backorders', 'int'),
85
        'min_sale_qty'                => array('min_cart_qty', 'float'),
86
        'use_config_min_sale_qty'     => array('use_config_min_sale_qty', 'int'),
87
        'max_sale_qty'                => array('max_cart_qty', 'float'),
88
        'use_config_max_sale_qty'     => array('use_config_max_sale_qty', 'int'),
89
        'is_in_stock'                 => array('is_in_stock', 'int'),
90
        'notify_stock_qty'            => array('notify_on_stock_below', 'float'),
91
        'use_config_notify_stock_qty' => array('use_config_notify_stock_qty', 'int'),
92
        'manage_stock'                => array('manage_stock', 'int'),
93
        'use_config_manage_stock'     => array('use_config_manage_stock', 'int'),
94
        'use_config_qty_increments'   => array('use_config_qty_increments', 'int'),
95
        'qty_increments'              => array('qty_increments', 'float'),
96
        'use_config_enable_qty_inc'   => array('use_config_enable_qty_inc', 'int'),
97
        'enable_qty_increments'       => array('enable_qty_increments', 'int'),
98
        'is_decimal_divided'          => array('is_decimal_divided', 'int'),
99
    );
100
101
    /**
102
     * The array with the available visibility keys.
103
     *
104
     * @var array
105
     */
106
    protected $availableVisibilities = array(
107
        'Not Visible Individually' => VisibilityKeys::VISIBILITY_NOT_VISIBLE,
108
        'Catalog'                  => VisibilityKeys::VISIBILITY_IN_CATALOG,
109
        'Search'                   => VisibilityKeys::VISIBILITY_IN_SEARCH,
110
        'Catalog, Search'          => VisibilityKeys::VISIBILITY_BOTH
111
    );
112
113
    /**
114
     * The default callback mappings for the Magento standard product attributes.
115
     *
116
     * @var array
117
     */
118
    protected $defaultCallbackMappings = array(
119
        'visibility'           => array('import_product.callback.visibility'),
120
        'tax_class_id'         => array('import_product.callback.tax.class'),
121
        'bundle_price_type'    => array('import_product_bundle.callback.bundle.type'),
122
        'bundle_sku_type'      => array('import_product_bundle.callback.bundle.type'),
123
        'bundle_weight_type'   => array('import_product_bundle.callback.bundle.type'),
124
        'bundle_price_view'    => array('import_product_bundle.callback.bundle.price.view'),
125
        'bundle_shipment_type' => array('import_product_bundle.callback.bundle.shipment.type')
126
    );
127
128
    /**
129
     * The available entity types.
130
     *
131
     * @var array
132
     */
133
    protected $entityTypes = array();
134
135
    /**
136
     * The media roles loader instance.
137
     *
138
     * @var \TechDivision\Import\Loaders\LoaderInterface
139
     */
140
    protected $mediaRolesLoader;
141
142
    /**
143
     * The entity type code mapper instance.
144
     *
145
     * @var \TechDivision\Import\Utils\Mappings\MapperInterface
146
     */
147
    protected $entityTypeCodeMapper;
148
149
    /**
150
     * BunchSubject constructor
151
     *
152
     * @param \TechDivision\Import\Services\RegistryProcessorInterface $registryProcessor          The registry processor instance
153
     * @param \TechDivision\Import\Utils\Generators\GeneratorInterface $coreConfigDataUidGenerator The UID generator for the core config data
154
     * @param \Doctrine\Common\Collections\Collection                  $systemLoggers              The array with the system loggers instances
155
     * @param \League\Event\EmitterInterface                           $emitter                    The event emitter instance
156
     * @param \TechDivision\Import\Loaders\LoaderInterface             $mediaRolesLoader           The media type loader instance
157
     * @param \TechDivision\Import\Utils\Mappings\MapperInterface      $entityTypeCodeMapper       The entity type code mapper instance
158
     */
159
    public function __construct(
160 18
        RegistryProcessorInterface $registryProcessor,
161
        GeneratorInterface $coreConfigDataUidGenerator,
162
        Collection $systemLoggers,
163
        EmitterInterface $emitter,
164
        LoaderInterface $mediaRolesLoader,
165
        MapperInterface $entityTypeCodeMapper
166
    ) {
167
168
        // set the loader for the media roles and the entity type code mapper
169
        $this->mediaRolesLoader = $mediaRolesLoader;
170 18
        $this->entityTypeCodeMapper = $entityTypeCodeMapper;
171 18
172
        // pass the other instances to the parent constructor
173
        parent::__construct($registryProcessor, $coreConfigDataUidGenerator, $systemLoggers, $emitter);
174 18
    }
175 18
176
    /**
177
     * Intializes the previously loaded global data for exactly one bunch.
178
     *
179
     * @param string $serial The serial of the actual import
180
     *
181
     * @return void
182
     */
183
    public function setUp($serial)
184 18
    {
185
186
        // load the status of the actual import
187
        $status = $this->getRegistryProcessor()->getAttribute(RegistryKeys::STATUS);
188 18
189
        // load the global data we've prepared initially
190
        $this->entityTypes = $status[RegistryKeys::GLOBAL_DATA][RegistryKeys::ENTITY_TYPES];
191 18
192
        // initialize the flag whether to copy images or not
193
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::COPY_IMAGES)) {
194 18
            $this->setCopyImages($this->getConfiguration()->getParam(ConfigurationKeys::COPY_IMAGES));
195
        }
196
197
        // initialize the flag whether to override images or not
198
        if ($this->getConfiguration()->hasParam(ConfigurationKeys::OVERRIDE_IMAGES)) {
199 18
            $this->setOverrideImages($this->getConfiguration()->getParam(ConfigurationKeys::OVERRIDE_IMAGES));
200
        }
201
202
        // initialize media directory => can be absolute or relative
203 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...
204 18
            try {
205
                $this->setMediaDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::MEDIA_DIRECTORY)));
206
            } catch (\InvalidArgumentException $iae) {
207
                $this->getSystemLogger()->debug($iae->getMessage());
208
            }
209
        }
210
211
        // initialize images directory => can be absolute or relative
212 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...
213 18
            try {
214
                $this->setImagesFileDir($this->resolvePath($this->getConfiguration()->getParam(ConfigurationKeys::IMAGES_FILE_DIRECTORY)));
215
            } catch (\InvalidArgumentException $iae) {
216
                $this->getSystemLogger()->debug($iae->getMessage());
217
            }
218
        }
219
220
        // invoke the parent method
221
        parent::setUp($serial);
222 18
    }
223 18
224
    /**
225
     * Clean up the global data after importing the bunch.
226
     *
227
     * @param string $serial The serial of the actual import
228
     *
229
     * @return void
230
     */
231
    public function tearDown($serial)
232
    {
233
234
        // invoke the parent method
235
        parent::tearDown($serial);
236
237
        // load the registry processor
238
        $registryProcessor = $this->getRegistryProcessor();
239
240
        // update the status
241
        $registryProcessor->mergeAttributesRecursive(
242
            RegistryKeys::STATUS,
243
            array(
244
                RegistryKeys::PRE_LOADED_ENTITY_IDS => $this->preLoadedEntityIds,
245
            )
246
        );
247
    }
248
249
    /**
250
     * Return's the default callback mappings.
251
     *
252
     * @return array The default callback mappings
253
     */
254
    public function getDefaultCallbackMappings()
255
    {
256
        return $this->defaultCallbackMappings;
257
    }
258
259
    /**
260
     * Return's the mappings for the table column => CSV column header.
261
     *
262
     * @return array The header stock mappings
263
     */
264
    public function getHeaderStockMappings()
265 1
    {
266
        return $this->headerStockMappings;
267 1
    }
268
269
    /**
270
     * Return's the visibility key for the passed visibility string.
271
     *
272
     * @param string $visibility The visibility string to return the key for
273
     *
274
     * @return integer The requested visibility key
275
     * @throws \Exception Is thrown, if the requested visibility is not available
276
     */
277
    public function getVisibilityIdByValue($visibility)
278
    {
279
280
        // query whether or not, the requested visibility is available
281
        if (isset($this->availableVisibilities[$visibility])) {
282
            // load the visibility ID, add the mapping and return the ID
283
            return $this->availableVisibilities[$visibility];
284
        }
285
286
        // throw an exception, if not
287
        throw new \Exception(
288
            $this->appendExceptionSuffix(
289
                sprintf('Found invalid visibility %s', $visibility)
290
            )
291
        );
292
    }
293
294
    /**
295
     * Pre-load the entity ID for the passed product.
296
     *
297
     * @param array $product The product to be pre-loaded
298
     *
299
     * @return void
300
     */
301
    public function preLoadEntityId(array $product)
302
    {
303
        $this->preLoadedEntityIds[$product[MemberNames::SKU]] = $product[MemberNames::ENTITY_ID];
304
    }
305
306
    /**
307
     * Return's the entity type for the configured entity type code.
308
     *
309
     * @return array The requested entity type
310
     * @throws \Exception Is thrown, if the requested entity type is not available
311
     */
312 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...
313 1
    {
314
315
        // query whether or not the entity type with the passed code is available
316
        if (isset($this->entityTypes[$entityTypeCode = $this->getEntityTypeCode()])) {
317 1
            return $this->entityTypes[$entityTypeCode];
318 1
        }
319
320
        // throw a new exception
321
        throw new \Exception(
322
            $this->appendExceptionSuffix(
323
                sprintf('Requested entity type "%s" is not available', $entityTypeCode)
324
            )
325
        );
326
    }
327
328
    /**
329
     * Loads and returns the media roles.
330
     *
331
     * @return array The array with the media roles
332
     */
333
    public function getMediaRoles(): array
334
    {
335
        return $this->mediaRolesLoader->load();
336
    }
337
338
    /**
339
     * Return's the entity type code to be used.
340
     *
341
     * @return string The entity type code to be used
342
     */
343
    public function getEntityTypeCode()
344
    {
345
        return $this->entityTypeCodeMapper->map(parent::getEntityTypeCode());
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->entityType...::getEntityTypeCode()); (string) is incompatible with the return type declared by the interface TechDivision\Import\Subj...face::getEntityTypeCode of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
346
    }
347
}
348