Completed
Push — 19.x ( 019ccc )
by Tim
02:02
created

BundleOptionObserver::addParentSkuNameMapping()   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 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Bundle\Observers\BundleOptionObserver
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-bundle
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Bundle\Observers;
22
23
use TechDivision\Import\Utils\StoreViewCodes;
24
use TechDivision\Import\Product\Bundle\Utils\ColumnKeys;
25
use TechDivision\Import\Product\Bundle\Utils\MemberNames;
26
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
27
use TechDivision\Import\Product\Bundle\Services\ProductBundleProcessorInterface;
28
29
/**
30
 * Oberserver that provides functionality for the bundle option replace operation.
31
 *
32
 * @author    Tim Wagner <[email protected]>
33
 * @copyright 2016 TechDivision GmbH <[email protected]>
34
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
35
 * @link      https://github.com/techdivision/import-product-bundle
36
 * @link      http://www.techdivision.com
37
 */
38
class BundleOptionObserver extends AbstractProductImportObserver
39
{
40
41
    /**
42
     * The product bundle processor instance.
43
     *
44
     * @var \TechDivision\Import\Product\Bundle\Services\ProductBundleProcessorInterface
45
     */
46
    protected $productBundleProcessor;
47
48
    /**
49
     * Initialize the observer with the passed product bundle processor instance.
50
     *
51
     * @param \TechDivision\Import\Product\Bundle\Services\ProductBundleProcessorInterface $productBundleProcessor The product bundle processor instance
52
     */
53
    public function __construct(ProductBundleProcessorInterface $productBundleProcessor)
54
    {
55
        $this->productBundleProcessor = $productBundleProcessor;
56
    }
57
58
    /**
59
     * Return's the product bundle processor instance.
60
     *
61
     * @return \TechDivision\Import\Product\Bundle\Services\ProductBundleProcessorInterface The product bundle processor instance
62
     */
63
    protected function getProductBundleProcessor()
64
    {
65
        return $this->productBundleProcessor;
66
    }
67
68
    /**
69
     * Process the observer's business logic.
70
     *
71
     * @return array The processed row
72
     */
73
    protected function process()
74
    {
75
76
        // prepare the store view code
77
        $this->prepareStoreViewCode($this->getRow());
0 ignored issues
show
Unused Code introduced by
The call to BundleOptionObserver::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...
78
79
        // return immediately if we're have no store view code set
80
        if (StoreViewCodes::ADMIN !== $this->getStoreViewCode(StoreViewCodes::ADMIN)) {
81
            return;
82
        }
83
84
        // load the name and the parent SKU
85
        $name = $this->getValue(ColumnKeys::BUNDLE_VALUE_NAME);
86
        $parentSku = $this->getValue(ColumnKeys::BUNDLE_PARENT_SKU);
87
88
        // query whether or not the option has already been created for the parent SKU
89
        if ($this->exists($parentSku, $name)) {
90
            return;
91
        }
92
93
        // load and persist the product bundle option
94
        $optionId = $this->persistProductBundleOption($this->initializeBundleOption($this->prepareAttributes()));
95
96
        // store the parent SKU => name mapping
97
        $this->addParentSkuNameMapping(array($parentSku => array($name => $optionId)));
98
    }
99
100
    /**
101
     * Prepare the attributes of the entity that has to be persisted.
102
     *
103
     * @return array The prepared attributes
104
     */
105
    protected function prepareAttributes()
106
    {
107
108
        // reset the position counter for the bundle selection
109
        $this->resetPositionCounter();
110
111
        try {
112
            // load and map the parent SKU
113
            $parentId = $this->mapSku($this->getValue(ColumnKeys::BUNDLE_PARENT_SKU));
114
        } catch (\Exception $e) {
115
            throw $this->wrapException(array(ColumnKeys::BUNDLE_PARENT_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...eys::BUNDLE_PARENT_SKU) 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...
116
        }
117
118
        // extract the parent/child ID as well as type and position
119
        $required = $this->getValue(ColumnKeys::BUNDLE_VALUE_REQUIRED);
120
        $type = $this->getValue(ColumnKeys::BUNDLE_VALUE_TYPE);
121
        $position = 1;
122
123
        // return the prepared product
124
        return $this->initializeEntity(
125
            array(
126
                MemberNames::PARENT_ID => $parentId,
127
                MemberNames::REQUIRED  => $required,
128
                MemberNames::POSITION  => $position,
129
                MemberNames::TYPE      => $type
130
            )
131
        );
132
    }
133
134
    /**
135
     * Initialize the bundle option with the passed attributes and returns an instance.
136
     *
137
     * @param array $attr The bundle option attributes
138
     *
139
     * @return array The initialized bundle option
140
     */
141
    protected function initializeBundleOption(array $attr)
142
    {
143
        return $attr;
144
    }
145
146
    /**
147
     * Reset the position counter to 1.
148
     *
149
     * @return void
150
     */
151
    protected function resetPositionCounter()
152
    {
153
        $this->getSubject()->resetPositionCounter();
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 resetPositionCounter() does only exist in the following implementations of said interface: TechDivision\Import\Prod...\Subjects\BundleSubject.

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...
154
    }
155
156
    /**
157
     * Add's the passed mapping to the subject.
158
     *
159
     * @param array $mapping The mapping to add
160
     *
161
     * @return void
162
     */
163
    protected function addParentSkuNameMapping($mapping = array())
164
    {
165
        $this->getSubject()->addParentSkuNameMapping($mapping);
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 addParentSkuNameMapping() does only exist in the following implementations of said interface: TechDivision\Import\Prod...\Subjects\BundleSubject.

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...
166
    }
167
168
    /**
169
     * Query whether or not the option for the passed parent SKU and name has already been created.
170
     *
171
     * @param string $parentSku The parent SKU to query for
172
     * @param string $name      The option name to query for
173
     *
174
     * @return boolean TRUE if the option already exists, else FALSE
175
     */
176
    protected function exists($parentSku, $name)
177
    {
178
        return $this->getSubject()->exists($parentSku, $name);
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 exists() does only exist in the following implementations of said interface: TechDivision\Import\Prod...\Subjects\BundleSubject.

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...
179
    }
180
181
    /**
182
     * Return the entity ID for the passed SKU.
183
     *
184
     * @param string $sku The SKU to return the entity ID for
185
     *
186
     * @return integer The mapped entity ID
187
     * @throws \Exception Is thrown if the SKU is not mapped yet
188
     */
189
    protected function mapSku($sku)
190
    {
191
        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...\Subjects\BundleSubject, TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject.

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...
192
    }
193
194
    /**
195
     * Persist's the passed product bundle option data and return's the ID.
196
     *
197
     * @param array $productBundleOption The product bundle option data to persist
198
     *
199
     * @return string The ID of the persisted entity
200
     */
201
    protected function persistProductBundleOption($productBundleOption)
202
    {
203
        return $this->getProductBundleProcessor()->persistProductBundleOption($productBundleOption);
204
    }
205
}
206