Completed
Push — master ( ee291f...d6b81e )
by Tim
11s
created

LinkObserver::mapSku()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

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
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Link\Observers\LinkObserver
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-link
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Link\Observers;
22
23
use TechDivision\Import\Product\Link\Utils\ColumnKeys;
24
use TechDivision\Import\Product\Link\Utils\MemberNames;
25
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
26
use TechDivision\Import\Product\Link\Services\ProductLinkProcessorInterface;
27
use TechDivision\Import\Product\Link\Exceptions\MapLinkTypeCodeToIdException;
28
29
/**
30
 * Oberserver that provides functionality for the product link 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-link
36
 * @link      http://www.techdivision.com
37
 */
38
class LinkObserver extends AbstractProductImportObserver
39
{
40
41
    /**
42
     * The product link processor instance.
43
     *
44
     * @var \TechDivision\Import\Product\Link\Services\ProductLinkProcessorInterface
45
     */
46
    protected $productLinkProcessor;
47
48
    /**
49
     * Initialize the observer with the passed product link processor instance.
50
     *
51
     * @param \TechDivision\Import\Product\Link\Services\ProductLinkProcessorInterface $productLinkProcessor The product link processor instance
52
     */
53
    public function __construct(ProductLinkProcessorInterface $productLinkProcessor)
54
    {
55
        $this->productLinkProcessor= $productLinkProcessor;
56
    }
57
58
    /**
59
     * Return's the product link processor instance.
60
     *
61
     * @return \TechDivision\Import\Product\Bundle\Services\ProductBundleProcessorInterface The product link processor instance
62
     */
63
    protected function getProductLinkProcessor()
64
    {
65
        return $this->productLinkProcessor;
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 product link entity
77
        if ($attr = $this->prepareAttributes()) {
78
            // initialize the product link entity
79
            $productLink = $this->initializeProductLink($attr);
80
81
            // persist the product link entity and store the link ID
82
            $this->setLastLinkId($this->persistProductLink($productLink));
83
        }
84
    }
85
86
    /**
87
     * Prepare the attributes of the entity that has to be persisted.
88
     *
89
     * @return array The prepared attributes
90
     */
91
    protected function prepareAttributes()
92
    {
93
94
        try {
95
            // extract the parent ID from the row
96
            $parentId = $this->mapSku($this->getValue(ColumnKeys::LINK_PARENT_SKU));
97
        } catch (\Exception $e) {
98
            throw $this->wrapException(array(ColumnKeys::LINK_PARENT_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...nKeys::LINK_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...
99
        }
100
101
        try {
102
            // extract the child ID from the row
103
            $childId = $this->mapSkuToEntityId($this->getValue(ColumnKeys::LINK_CHILD_SKU));
104
        } catch (\Exception $e) {
105
            throw $this->wrapException(array(ColumnKeys::LINK_CHILD_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...mnKeys::LINK_CHILD_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...
106
        }
107
108
        try {
109
            // extract the link type code from the row
110
            $linkTypeId = $this->mapLinkTypeCodeToLinkTypeId($this->getValue(ColumnKeys::LINK_TYPE_CODE));
111
        } catch (\Exception $e) {
112
            // query whether or not, debug mode is enabled
113
            if ($this->isDebugMode()) {
114
                // log a warning and return immediately
115
                $this->getSystemLogger()->warning($e->getMessage());
116
                return;
117
            }
118
119
            // if we're NOT in debug mode, re-throw the exception
120
            throw $e;
121
        }
122
123
        // initialize and return the entity
124
        return $this->initializeEntity(
125
            array(
126
                MemberNames::PRODUCT_ID        => $parentId,
127
                MemberNames::LINKED_PRODUCT_ID => $childId,
128
                MemberNames::LINK_TYPE_ID      => $linkTypeId
129
            )
130
        );
131
    }
132
133
    /**
134
     * Initialize the product link with the passed attributes and returns an instance.
135
     *
136
     * @param array $attr The product link attributes
137
     *
138
     * @return array The initialized product link
139
     */
140
    protected function initializeProductLink(array $attr)
141
    {
142
        return $attr;
143
    }
144
145
    /**
146
     * Temporary persist the last link ID.
147
     *
148
     * @param integer $lastLinkId The last link ID
149
     *
150
     * @return void
151
     */
152
    protected function setLastLinkId($lastLinkId)
153
    {
154
        $this->getSubject()->setLastLinkId($lastLinkId);
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 setLastLinkId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...nk\Subjects\LinkSubject.

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...
155
    }
156
157
    /**
158
     * Persist's the passed product link data and return's the ID.
159
     *
160
     * @param array $productLink The product link data to persist
161
     *
162
     * @return string The ID of the persisted entity
163
     */
164
    protected function persistProductLink($productLink)
165
    {
166
        return $this->getProductLinkProcessor()->persistProductLink($productLink);
167
    }
168
169
    /**
170
     * Return the entity ID for the passed SKU.
171
     *
172
     * @param string $sku The SKU to return the entity ID for
173
     *
174
     * @return integer The mapped entity ID
175
     * @throws \TechDivision\Import\Product\Link\Exceptions\MapSkuToEntityIdException Is thrown if the SKU is not mapped yet
176
     */
177
    protected function mapSkuToEntityId($sku)
178
    {
179
        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...nk\Subjects\LinkSubject.

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

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...
193
    }
194
195
    /**
196
     * Return the link type ID for the passed link type code.
197
     *
198
     * @param string $linkTypeCode The link type code to return the link type ID for
199
     *
200
     * @return integer The mapped link type ID
201
     * @throws \TechDivision\Import\Product\Link\Exceptions\MapLinkTypeCodeToIdException Is thrown if the link type code is not mapped yet
202
     */
203
    protected function mapLinkTypeCodeToLinkTypeId($linkTypeCode)
204
    {
205
        return $this->getSubject()->mapLinkTypeCodeToLinkTypeId($linkTypeCode);
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 mapLinkTypeCodeToLinkTypeId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...nk\Subjects\LinkSubject.

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...
206
    }
207
208
    /**
209
     * Queries whether or not debug mode is enabled or not, default is TRUE.
210
     *
211
     * @return boolean TRUE if debug mode is enabled, else FALSE
212
     */
213
    protected function isDebugMode()
214
    {
215
        return $this->getSubject()->isDebugMode();
216
    }
217
}
218