Completed
Push — master ( 25a706...762587 )
by Tim
12s
created

getEavAttributeByAttributeCode()   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\Media\Observers\MediaGalleryObserver
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-media
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Media\Observers;
22
23
use TechDivision\Import\Product\Media\Utils\ColumnKeys;
24
use TechDivision\Import\Product\Media\Utils\MemberNames;
25
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
26
use TechDivision\Import\Product\Media\Services\ProductMediaProcessorInterface;
27
28
/**
29
 * Observer that creates/updates the product's media gallery information.
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-media
35
 * @link      http://www.techdivision.com
36
 */
37
class MediaGalleryObserver extends AbstractProductImportObserver
38
{
39
40
    /**
41
     * The media gallery attribute code.
42
     *
43
     * @var string
44
     */
45
    const ATTRIBUTE_CODE = 'media_gallery';
46
47
    /**
48
     * The ID of the parent product the media is related to.
49
     *
50
     * @var integer
51
     */
52
    protected $parentId;
53
54
    /**
55
     * The ID of the persisted media gallery entity.
56
     *
57
     * @var integer
58
     */
59
    protected $valueId;
60
61
    /**
62
     * The product media processor instance.
63
     *
64
     * @var \TechDivision\Import\Product\Media\Services\ProductMediaProcessorInterface
65
     */
66
    protected $productMediaProcessor;
67
68
    /**
69
     * Initialize the observer with the passed product media processor instance.
70
     *
71
     * @param \TechDivision\Import\Product\Media\Services\ProductMediaProcessorInterface $productMediaProcessor The product media processor instance
72
     */
73
    public function __construct(ProductMediaProcessorInterface $productMediaProcessor)
74
    {
75
        $this->productMediaProcessor = $productMediaProcessor;
76
    }
77
78
    /**
79
     * Return's the product media processor instance.
80
     *
81
     * @return \TechDivision\Import\Product\Media\Services\ProductMediaProcessorInterface The product media processor instance
82
     */
83
    protected function getProductMediaProcessor()
84
    {
85
        return $this->productMediaProcessor;
86
    }
87
88
    /**
89
     * Process the observer's business logic.
90
     *
91
     * @return array The processed row
92
     */
93
    protected function process()
94
    {
95
96
        // query whether or not, the image changed
97
        if ($this->isParentImage($this->getValue(ColumnKeys::IMAGE_PATH))) {
98
            return;
99
        }
100
101
        try {
102
            // try to load the product SKU and map it the entity ID
103
            $this->parentId = $this->getValue(ColumnKeys::IMAGE_PARENT_SKU, null, array($this, 'mapParentSku'));
104
        } catch (\Exception $e) {
105
            throw $this->wrapException(array(ColumnKeys::IMAGE_PARENT_SKU), $e);
0 ignored issues
show
Documentation introduced by
array(\TechDivision\Impo...Keys::IMAGE_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...
106
        }
107
108
        // reset the position counter for the product media gallery value
109
        $this->resetPositionCounter();
110
111
        // initialize and persist the product media gallery
112
        $productMediaGallery = $this->initializeProductMediaGallery($this->prepareProductMediaGalleryAttributes());
113
        $this->valueId = $this->persistProductMediaGallery($productMediaGallery);
0 ignored issues
show
Documentation Bug introduced by
The property $valueId was declared of type integer, but $this->persistProductMed...y($productMediaGallery) is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
114
115
        // persist the product media gallery to entity data
116
        if ($productMediaGalleryValueToEntity = $this->initializeProductMediaGalleryValueToEntity($this->prepareProductMediaGalleryValueToEntityAttributes())) {
117
            $this->persistProductMediaGalleryValueToEntity($productMediaGalleryValueToEntity);
118
        }
119
120
        // temporarily persist parent/value ID
121
        $this->setParentId($this->parentId);
122
        $this->setParentValueId($this->valueId);
123
    }
124
125
    /**
126
     * Prepare the product media gallery that has to be persisted.
127
     *
128
     * @return array The prepared product media gallery attributes
129
     */
130
    protected function prepareProductMediaGalleryAttributes()
131
    {
132
133
        // load the attribute ID of the media gallery EAV attribute
134
        $mediaGalleryAttribute = $this->getEavAttributeByAttributeCode(MediaGalleryObserver::ATTRIBUTE_CODE);
135
        $attributeId = $mediaGalleryAttribute[MemberNames::ATTRIBUTE_ID];
136
137
        // initialize the gallery data
138
        $disabled = 0;
139
        $mediaType = 'image';
140
        $image = $this->getValue(ColumnKeys::IMAGE_PATH_NEW);
141
142
        // initialize and return the entity
143
        return $this->initializeEntity(
144
            array(
145
                MemberNames::ATTRIBUTE_ID => $attributeId,
146
                MemberNames::VALUE        => $image,
147
                MemberNames::MEDIA_TYPE   => $mediaType,
148
                MemberNames::DISABLED     => $disabled
149
            )
150
        );
151
    }
152
153
    /**
154
     * Prepare the product media gallery value to entity that has to be persisted.
155
     *
156
     * @return array The prepared product media gallery value to entity attributes
157
     */
158
    protected function prepareProductMediaGalleryValueToEntityAttributes()
159
    {
160
161
        // initialize and return the entity
162
        return $this->initializeEntity(
163
            array(
164
                MemberNames::VALUE_ID  => $this->valueId,
165
                MemberNames::ENTITY_ID => $this->parentId
166
            )
167
        );
168
    }
169
170
    /**
171
     * Initialize the product media gallery with the passed attributes and returns an instance.
172
     *
173
     * @param array $attr The product media gallery attributes
174
     *
175
     * @return array The initialized product media gallery
176
     */
177
    protected function initializeProductMediaGallery(array $attr)
178
    {
179
        return $attr;
180
    }
181
182
    /**
183
     * Initialize the product media gallery value to entity with the passed attributes and returns an instance.
184
     *
185
     * @param array $attr The product media gallery value to entity attributes
186
     *
187
     * @return array|null The initialized product media gallery value to entity, or NULL if the product media gallery value to entity already exists
188
     */
189
    protected function initializeProductMediaGalleryValueToEntity(array $attr)
190
    {
191
        return $attr;
192
    }
193
194
    /**
195
     * Map's the passed SKU of the parent product to it's PK.
196
     *
197
     * @param string $parentSku The SKU of the parent product
198
     *
199
     * @return integer The primary key used to create relations
200
     */
201
    protected function mapParentSku($parentSku)
202
    {
203
        return $this->mapSkuToEntityId($parentSku);
204
    }
205
206
    /**
207
     * Return's the name of the created image.
208
     *
209
     * @return string The name of the created image
210
     */
211
    protected function getParentImage()
212
    {
213
        return $this->getSubject()->getParentImage();
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 getParentImage() does only exist in the following implementations of said interface: TechDivision\Import\Prod...a\Subjects\MediaSubject.

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...
214
    }
215
216
    /**
217
     * Return's TRUE if the passed image is the parent one.
218
     *
219
     * @param string $image The imageD to check
220
     *
221
     * @return boolean TRUE if the passed image is the parent one
222
     */
223
    protected function isParentImage($image)
224
    {
225
        return $this->getParentImage() === $image;
226
    }
227
228
    /**
229
     * Set's the value ID of the created media gallery entry.
230
     *
231
     * @param integer $parentValueId The ID of the created media gallery entry
232
     *
233
     * @return void
234
     */
235
    protected function setParentValueId($parentValueId)
236
    {
237
        $this->getSubject()->setParentValueId($parentValueId);
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 setParentValueId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...a\Subjects\MediaSubject.

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...
238
    }
239
240
    /**
241
     * Return the entity ID for the passed SKU.
242
     *
243
     * @param string $sku The SKU to return the entity ID for
244
     *
245
     * @return integer The mapped entity ID
246
     * @throws \Exception Is thrown if the SKU is not mapped yet
247
     */
248
    protected function mapSkuToEntityId($sku)
249
    {
250
        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...a\Subjects\MediaSubject.

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...
251
    }
252
253
    /**
254
     * Set's the ID of the parent product to relate the variant with.
255
     *
256
     * @param integer $parentId The ID of the parent product
257
     *
258
     * @return void
259
     */
260
    protected function setParentId($parentId)
261
    {
262
        $this->getSubject()->setParentId($parentId);
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 setParentId() does only exist in the following implementations of said interface: TechDivision\Import\Prod...a\Subjects\MediaSubject.

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...
263
    }
264
265
    /**
266
     * Reset the position counter to 1.
267
     *
268
     * @return void
269
     */
270
    protected function resetPositionCounter()
271
    {
272
        $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...a\Subjects\MediaSubject.

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...
273
    }
274
275
    /**
276
     * Return's the EAV attribute with the passed attribute code.
277
     *
278
     * @param string $attributeCode The attribute code
279
     *
280
     * @return array The array with the EAV attribute
281
     * @throws \Exception Is thrown if the attribute with the passed code is not available
282
     */
283
    protected function getEavAttributeByAttributeCode($attributeCode)
284
    {
285
        return $this->getSubject()->getEavAttributeByAttributeCode($attributeCode);
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 getEavAttributeByAttributeCode() does only exist in the following implementations of said interface: TechDivision\Import\Prod...a\Subjects\MediaSubject, TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Subjects\AbstractEavSubject.

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...
286
    }
287
288
    /**
289
     * Persist's the passed product media gallery data and return's the ID.
290
     *
291
     * @param array $productMediaGallery The product media gallery data to persist
292
     *
293
     * @return string The ID of the persisted entity
294
     */
295
    protected function persistProductMediaGallery($productMediaGallery)
296
    {
297
        return $this->getProductMediaProcessor()->persistProductMediaGallery($productMediaGallery);
298
    }
299
300
    /**
301
     * Persist's the passed product media gallery value to entity data.
302
     *
303
     * @param array $productMediaGalleryValueToEntity The product media gallery value to entity data to persist
304
     *
305
     * @return void
306
     */
307
    protected function persistProductMediaGalleryValueToEntity($productMediaGalleryValueToEntity)
308
    {
309
        $this->getProductMediaProcessor()->persistProductMediaGalleryValueToEntity($productMediaGalleryValueToEntity);
310
    }
311
}
312