Completed
Push — 10.x ( 7c9279 )
by Tim
03:22
created

prepareProductSuperLinkAttributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 9
cp 0
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\Variant\Observers\VariantSuperLinkObserver
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-variant
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Variant\Observers;
22
23
use TechDivision\Import\Product\Utils\RelationTypes;
24
use TechDivision\Import\Product\Variant\Utils\ColumnKeys;
25
use TechDivision\Import\Product\Variant\Utils\MemberNames;
26
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
27
use TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface;
28
29
/**
30
 * Oberserver that provides functionality for the product variant super 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-variant
36
 * @link      http://www.techdivision.com
37
 */
38
class VariantSuperLinkObserver extends AbstractProductImportObserver
39
{
40
41
    /**
42
     * The product variant processor instance.
43
     *
44
     * @var \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface
45
     */
46
    protected $productVariantProcessor;
47
48
    /**
49
     * Initialize the observer with the passed product variant processor instance.
50
     *
51
     * @param \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface $productVariantProcessor The product variant processor instance
52
     */
53
    public function __construct(ProductVariantProcessorInterface $productVariantProcessor)
54
    {
55
        $this->productVariantProcessor = $productVariantProcessor;
56
    }
57
58
    /**
59
     * Return's the product variant processor instance.
60
     *
61
     * @return \TechDivision\Import\Product\Variant\Services\ProductVariantProcessorInterface The product variant processor instance
62
     */
63
    protected function getProductVariantProcessor()
64
    {
65
        return $this->productVariantProcessor;
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
        // load the parent/child SKUs
77
        $parentSku = $this->getValue(ColumnKeys::VARIANT_PARENT_SKU);
78
        $childSku = $this->getValue(ColumnKeys::VARIANT_CHILD_SKU);
79
80
        // query whether or not the super link has already been processed
81
        if ($this->hasBeenProcessedRelation($parentSku, $childSku, RelationTypes::VARIANT_SUPER_LINK)) {
82
            return;
83
        }
84
85
        try {
86
            // try to load and map the parent ID
87
            $this->parentId = $this->mapSku($parentSku);
0 ignored issues
show
Bug introduced by
The property parentId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
88
        } catch (\Exception $e) {
89
            throw $this->wrapException(array(ColumnKeys::VARIANT_PARENT_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...ys::VARIANT_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...
Deprecated Code introduced by
The method TechDivision\Import\Obse...server::wrapException() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
90
        }
91
92
        try {
93
            // try to load and map the child ID
94
            $this->childId = $this->mapChildSku($childSku);
0 ignored issues
show
Bug introduced by
The property childId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
95
        } catch (\Exception $e) {
96
            throw $this->wrapException(array(ColumnKeys::VARIANT_CHILD_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...eys::VARIANT_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...
Deprecated Code introduced by
The method TechDivision\Import\Obse...server::wrapException() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
97
        }
98
99
        try {
100
            // prepare and persist the product super link
101
            if ($productSuperLink = $this->initializeProductSuperLink($this->prepareProductSuperLinkAttributes())) {
102
                $this->persistProductSuperLink($productSuperLink);
103
            }
104
105
            // mark the super link as processed
106
            $this->addProcessedRelation($parentSku, $childSku, RelationTypes::VARIANT_SUPER_LINK);
107
        } catch (\Exception $e) {
108
            // prepare a more detailed error message
109
            $message = $this->appendExceptionSuffix(
0 ignored issues
show
Deprecated Code introduced by
The method TechDivision\Import\Obse...appendExceptionSuffix() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
110
                sprintf(
111
                    'Super link with SKUs %s => %s can\'t be created',
112
                    $parentSku,
113
                    $childSku
114
                )
115
            );
116
117
            // if we're NOT in debug mode, re-throw a more detailed exception
118
            $wrappedException = $this->wrapException(
0 ignored issues
show
Deprecated Code introduced by
The method TechDivision\Import\Obse...server::wrapException() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
119
                array(ColumnKeys::VARIANT_PARENT_SKU, ColumnKeys::VARIANT_CHILD_SKU),
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...eys::VARIANT_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...
120
                new \Exception($message, null, $e)
121
            );
122
123
            // query whether or not, debug mode is enabled
124
            if ($this->isDebugMode()) {
0 ignored issues
show
Deprecated Code introduced by
The method TechDivision\Import\Obse...Observer::isDebugMode() has been deprecated with message: Will be removed with version 1.0.0, use subject method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
125
                // log a warning and return immediately
126
                $this->getSystemLogger()->warning($wrappedException->getMessage());
127
                return;
128
            }
129
130
            // else, throw the exception
131
            throw $wrappedException;
132
        }
133
    }
134
135
    /**
136
     * Prepare the product super link attributes that has to be persisted.
137
     *
138
     * @return array The prepared product super link attributes
139
     */
140
    protected function prepareProductSuperLinkAttributes()
141
    {
142
143
        // initialize and return the entity
144
        return $this->initializeEntity(
145
            array(
146
                MemberNames::PRODUCT_ID => $this->childId,
147
                MemberNames::PARENT_ID  => $this->parentId
148
            )
149
        );
150
    }
151
152
    /**
153
     * Initialize the product super link with the passed attributes and returns an instance.
154
     *
155
     * @param array $attr The product super link attributes
156
     *
157
     * @return array|null The initialized product super link, or null if the super link already exsist
158
     */
159
    protected function initializeProductSuperLink(array $attr)
160
    {
161
        return $attr;
162
    }
163
164
    /**
165
     * Return the entity ID for the passed SKU.
166
     *
167
     * @param string $sku The SKU to return the entity ID for
168
     *
169
     * @return integer The mapped entity ID
170
     * @throws \Exception Is thrown if the SKU is not mapped yet
171
     */
172
    protected function mapSku($sku)
173
    {
174
        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\VariantSubject.

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...
175
    }
176
177
    /**
178
     * Return the entity ID for the passed child SKU.
179
     *
180
     * @param string $sku The SKU to return the entity ID for
181
     *
182
     * @return integer The mapped entity ID
183
     * @throws \Exception Is thrown if the SKU is not mapped yet
184
     */
185
    protected function mapChildSku($sku)
186
    {
187
        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\VariantSubject.

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...
188
    }
189
190
    /**
191
     * Persist's the passed product super link data and return's the ID.
192
     *
193
     * @param array $productSuperLink The product super link data to persist
194
     *
195
     * @return void
196
     */
197
    protected function persistProductSuperLink($productSuperLink)
198
    {
199
        return $this->getProductVariantProcessor()->persistProductSuperLink($productSuperLink);
200
    }
201
}
202