Completed
Push — 19.x ( 63ae15 )
by Tim
03:23
created

ProductWebsiteObserver::loadProductWebsitesBySku()   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 2
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\Observers\ProductWebsiteObserver
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\Observers;
22
23
use TechDivision\Import\Product\Services\ProductBunchProcessorInterface;
24
use TechDivision\Import\Product\Utils\ColumnKeys;
25
use TechDivision\Import\Product\Utils\MemberNames;
26
use TechDivision\Import\Product\Utils\ConfigurationKeys;
27
28
/**
29
 * Observer that creates/updates the product's website relations.
30
 *
31
 * @author    Tim Wagner <[email protected]>
32
 * @copyright 2016 TechDivision GmbH <[email protected]>
33
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
 * @link      https://github.com/techdivision/import-product
35
 * @link      http://www.techdivision.com
36
 */
37
class ProductWebsiteObserver extends AbstractProductImportObserver
38
{
39
40
    /**
41
     * The product bunch processor instance.
42
     *
43
     * @var \TechDivision\Import\Product\Services\ProductBunchProcessorInterface
44
     */
45
    protected $productBunchProcessor;
46
47
    /**
48
     * Initialize the observer with the passed product bunch processor instance.
49
     *
50
     * @param \TechDivision\Import\Product\Services\ProductBunchProcessorInterface $productBunchProcessor The product bunch processor instance
51
     */
52 1
    public function __construct(ProductBunchProcessorInterface $productBunchProcessor)
53
    {
54 1
        $this->productBunchProcessor = $productBunchProcessor;
55 1
    }
56
57
    /**
58
     * Return's the product bunch processor instance.
59
     *
60
     * @return \TechDivision\Import\Product\Services\ProductBunchProcessorInterface The product bunch processor instance
61
     */
62
    protected function getProductBunchProcessor()
63
    {
64
        return $this->productBunchProcessor;
65
    }
66
67
    /**
68
     * The actual website code that has to be processed.
69
     *
70
     * @var string
71
     */
72
    protected $code;
73
74
    /**
75
     * Set's the actual website code that has to be processed.
76
     *
77
     * @param string $code The website code
78
     *
79
     * @return void
80
     */
81
    protected function setCode($code)
82
    {
83
        $this->code = $code;
84
    }
85
86
    /**
87
     * Return's the webiste code that has to be processed.
88
     *
89
     * @return string The website code
90
     */
91
    protected function getCode()
92
    {
93
        return $this->code;
94
    }
95
96
    /**
97
     * Process the observer's business logic.
98
     *
99
     * @return array The processed row
100
     */
101 1
    protected function process()
102
    {
103
104
        // query whether or not, we've found a new SKU => means we've found a new product
105 1
        if ($this->hasBeenProcessed($sku = $this->getValue(ColumnKeys::SKU))) {
106
            return;
107
        }
108
109
        // load the product => website relations
110 1
        $codes = $this->getValue(ColumnKeys::PRODUCT_WEBSITES, array(), array($this, 'explode'));
111
112
        // query whether or not we've to clean up existing website product relations
113 1
        if ($this->getSubject()->getConfiguration()->hasParam(ConfigurationKeys::CLEAN_UP_WEBSITE_PRODUCT_RELATIONS) &&
114
            $this->getSubject()->getConfiguration()->getParam(ConfigurationKeys::CLEAN_UP_WEBSITE_PRODUCT_RELATIONS)
115
        ) {
116
117
            // initialize the array for the website IDs
118
            $websiteIds = array();
119
120
            // prepare the website IDs
121
            foreach ($codes as $code) {
122
                $websiteIds[$code] = $this->getStoreWebsiteIdByCode($code);
123
            }
124
125
            // load the available product websites
126
            if ($productWebsites = $this->loadProductWebsitesBySku($sku)) {
127
                // iterate over the products websites
128
                foreach ($productWebsites as $productWebsite) {
129
                    // if the product websit relation is in the CSV file, do nothing
130
                    if (in_array($productWebsite[MemberNames::WEBSITE_ID], $websiteIds)) {
131
                        continue;
132
                    }
133
134
                    // delete it, because we don't need it any longer
135
                    $this->deleteProductWebsite(
136
                        $productWebsite[MemberNames::PRODUCT_ID],
137
                        $productWebsite[MemberNames::WEBSITE_ID]
0 ignored issues
show
Unused Code introduced by
The call to ProductWebsiteObserver::deleteProductWebsite() has too many arguments starting with $productWebsite[\TechDiv...emberNames::WEBSITE_ID].

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...
138
                    );
139
                }
140
            }
141
        }
142
143
        // append the product => website relations found
144
        foreach ($codes as $code) {
145
            // set the code of the website that has to be processed
146
            $this->setCode($code);
147
            // prepare the product website relation attributes
148
            $attr = $this->prepareAttributes();
149
150
            try {
151
                // create the product website relation
152
                $productWebsite = $this->initializeProductWebsite($attr);
153
                $this->persistProductWebsite($productWebsite);
154
            } catch (\RuntimeException $re) {
155
                $this->getSystemLogger()->debug($re->getMessage());
156
            }
157
        }
158
    }
159
160
    /**
161
     * Prepare the attributes of the entity that has to be persisted.
162
     *
163
     * @return array The prepared attributes
164
     */
165
    protected function prepareAttributes()
166
    {
167
168
        // load the ID of the product that has been created recently
169
        $lastEntityId = $this->getLastEntityId();
0 ignored issues
show
Deprecated Code introduced by
The method TechDivision\Import\Obse...rver::getLastEntityId() 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...
170
171
        // load the website ID to relate the product with
172
        $websiteId = $this->getStoreWebsiteIdByCode($this->getCode());
173
174
        // return the prepared product
175
        return $this->initializeEntity(
176
            array(
177
                MemberNames::PRODUCT_ID => $lastEntityId,
178
                MemberNames::WEBSITE_ID => $websiteId
179
            )
180
        );
181
    }
182
183
    /**
184
     * Initialize the product website with the passed attributes and returns an instance.
185
     *
186
     * @param array $attr The product website attributes
187
     *
188
     * @return array The initialized product website
189
     * @throws \RuntimeException Is thrown, if the attributes can not be initialized
190
     */
191
    protected function initializeProductWebsite(array $attr)
192
    {
193
        return $attr;
194
    }
195
196
    /**
197
     * Load's and return's the product website relations for the product with the passed SKU.
198
     *
199
     * @param string $sku The SKU to of the product to load the product website relations for
200
     *
201
     * @return array The product website relations
202
     */
203
    protected function loadProductWebsitesBySku($sku)
204
    {
205
        return $this->getProductBunchProcessor()->loadProductWebsitesBySku($sku);
206
    }
207
208
    /**
209
     * Persist's the passed product website data.
210
     *
211
     * @param array $productWebsite The product website data to persist
212
     *
213
     * @return void
214
     */
215
    protected function persistProductWebsite(array $productWebsite)
216
    {
217
        $this->getProductBunchProcessor()->persistProductWebsite($productWebsite);
218
    }
219
220
    /**
221
     * Delete's the passed product website data.
222
     *
223
     * @param array $productWebsite The product website data to delete
224
     *
225
     * @return void
226
     */
227
    protected function deleteProductWebsite(array $productWebsite)
228
    {
229
        $this->getProductBunchProcessor()->deleteProductWebsite($productWebsite);
230
    }
231
232
    /**
233
     * Return's the store website for the passed code.
234
     *
235
     * @param string $code The code of the store website to return the ID for
236
     *
237
     * @return integer The store website ID
238
     */
239
    protected function getStoreWebsiteIdByCode($code)
240
    {
241
        return $this->getSubject()->getStoreWebsiteIdByCode($code);
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 getStoreWebsiteIdByCode() does only exist in the following implementations of said interface: 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...
242
    }
243
}
244