Completed
Push — master ( 381fd2...7bc757 )
by Tim
12s queued 10s
created

ProductUrlRewriteObserver::process()   C

Complexity

Conditions 9
Paths 7

Size

Total Lines 81

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 81
ccs 0
cts 52
cp 0
rs 6.8589
c 0
b 0
f 0
cc 9
nc 7
nop 0
crap 90

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * TechDivision\Import\Product\UrlRewrite\Observers\ProductUrlRewriteObserver
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-url-rewrite
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\UrlRewrite\Observers;
22
23
use TechDivision\Import\Utils\StoreViewCodes;
24
use TechDivision\Import\Product\UrlRewrite\Utils\ColumnKeys;
25
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
26
27
/**
28
 * Observer that extracts the URL rewrite data to a specific CSV file.
29
 *
30
 * @author    Tim Wagner <[email protected]>
31
 * @copyright 2016 TechDivision GmbH <[email protected]>
32
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
33
 * @link      https://github.com/techdivision/import-product-url-rewrite
34
 * @link      http://www.techdivision.com
35
 */
36
class ProductUrlRewriteObserver extends AbstractProductImportObserver
37
{
38
39
    /**
40
     * The artefact type.
41
     *
42
     * @var string
43
     */
44
    const ARTEFACT_TYPE = 'url-rewrite';
45
46
    /**
47
     * The image artefacts that has to be exported.
48
     *
49
     * @var array
50
     */
51
    protected $artefacts = array();
52
53
    /**
54
     * Process the observer's business logic.
55
     *
56
     * @return array The processed row
57
     */
58
    protected function process()
59
    {
60
61
        // initialize the array for the artefacts and the store view codes
62
        $this->artefacts = array();
63
        $storeViewCodes = array();
64
65
        // load the SKU from the row
66
        $sku = $this->getValue(ColumnKeys::SKU);
67
68
        // prepare the store view code
69
        $this->getSubject()->prepareStoreViewCode();
70
71
        // try to load the store view code
72
        $storeViewCode = $this->getSubject()->getStoreViewCode(StoreViewCodes::ADMIN);
73
74
        // query whether or not we've a store view code
75
        if ($storeViewCode === StoreViewCodes::ADMIN) {
76
            // if not, load the websites the product is related with
77
            $websiteCodes = $this->getValue(ColumnKeys::PRODUCT_WEBSITES, array(), array($this, 'explode'));
78
79
            // load the store view codes of all websites
80
            foreach ($websiteCodes as $websiteCode) {
81
                $storeViewCodes = array_merge($storeViewCodes, $this->getStoreViewCodesByWebsiteCode($websiteCode));
82
            }
83
        } else {
84
            array_push($storeViewCodes, $storeViewCode);
85
        }
86
87
        // iterate over the available image fields
88
        foreach ($storeViewCodes as $storeViewCode) {
89
            // iterate over the store view codes and query if artefacts are already available
90
            if ($this->hasArtefactsByTypeAndEntityId(ProductUrlRewriteObserver::ARTEFACT_TYPE, $lastEntityId = $this->getSubject()->getLastEntityId())) {
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 getLastEntityId() does only exist in the following implementations of said interface: TechDivision\Import\Observers\EntitySubjectImpl, TechDivision\Import\Plugins\ExportableSubjectImpl, TechDivision\Import\Prod...\AbstractProductSubject, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Prod...jects\UrlRewriteSubject, TechDivision\Import\Subjects\ExportableTraitImpl.

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...
91
                // if yes, load the artefacs
92
                $this->artefacts = $this->getArtefactsByTypeAndEntityId(ProductUrlRewriteObserver::ARTEFACT_TYPE, $lastEntityId);
93
94
                // override the existing data with the store view specific one
95
                for ($i = 0; $i < sizeof($this->artefacts); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
96
                    // query whether or not a URL key has be specfied and the store view codes are equal
97
                    if ($this->hasValue(ColumnKeys::URL_KEY) && $this->artefacts[$i][ColumnKeys::STORE_VIEW_CODE] === $storeViewCode) {
98
                        // update the URL key
99
                        $this->artefacts[$i][ColumnKeys::URL_KEY]    = $this->getValue(ColumnKeys::URL_KEY);
100
                        // update the visibility, if available
101
                        if ($this->hasValue(ColumnKeys::VISIBILITY)) {
102
                            $this->artefacts[$i][ColumnKeys::VISIBILITY] = $this->getValue(ColumnKeys::VISIBILITY);
103
                        }
104
105
                        // also update filename and line number
106
                        $this->artefacts[$i][ColumnKeys::ORIGINAL_DATA][ColumnKeys::ORIGINAL_FILENAME] = $this->getSubject()->getFilename();
107
                        $this->artefacts[$i][ColumnKeys::ORIGINAL_DATA][ColumnKeys::ORIGINAL_LINE_NUMBER] = $this->getSubject()->getLineNumber();
108
                    }
109
                }
110
            } else {
111
                // if no arefacts are available, append new data
112
                $artefact = $this->newArtefact(
113
                    array(
114
                        ColumnKeys::SKU                => $sku,
115
                        ColumnKeys::STORE_VIEW_CODE    => $storeViewCode,
116
                        ColumnKeys::CATEGORIES         => $this->getValue(ColumnKeys::CATEGORIES),
117
                        ColumnKeys::PRODUCT_WEBSITES   => $this->getValue(ColumnKeys::PRODUCT_WEBSITES),
118
                        ColumnKeys::VISIBILITY         => $this->getValue(ColumnKeys::VISIBILITY),
119
                        ColumnKeys::URL_KEY            => $this->getValue(ColumnKeys::URL_KEY)
120
                    ),
121
                    array(
122
                        ColumnKeys::SKU                => ColumnKeys::SKU,
123
                        ColumnKeys::STORE_VIEW_CODE    => ColumnKeys::STORE_VIEW_CODE,
124
                        ColumnKeys::CATEGORIES         => ColumnKeys::CATEGORIES,
125
                        ColumnKeys::PRODUCT_WEBSITES   => ColumnKeys::PRODUCT_WEBSITES,
126
                        ColumnKeys::VISIBILITY         => ColumnKeys::VISIBILITY,
127
                        ColumnKeys::URL_KEY            => ColumnKeys::URL_KEY,
128
                    )
129
                );
130
131
                // append the base image to the artefacts
132
                $this->artefacts[] = $artefact;
133
            }
134
        }
135
136
        // append the artefacts that has to be exported to the subject
137
        $this->addArtefacts($this->artefacts);
138
    }
139
140
    /**
141
     * Returns an array with the codes of the store views related with the passed website code.
142
     *
143
     * @param string $websiteCode The code of the website to return the store view codes for
144
     *
145
     * @return array The array with the matching store view codes
146
     */
147
    protected function getStoreViewCodesByWebsiteCode($websiteCode)
148
    {
149
        return $this->getSubject()->getStoreViewCodesByWebsiteCode($websiteCode);
0 ignored issues
show
Bug introduced by
The method getStoreViewCodesByWebsiteCode() does not exist on TechDivision\Import\Subjects\SubjectInterface. Did you maybe mean getStoreViewCode()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
150
    }
151
152
    /**
153
     * Queries whether or not artefacts for the passed type and entity ID are available.
154
     *
155
     * @param string $type     The artefact type, e. g. configurable
156
     * @param string $entityId The entity ID to return the artefacts for
157
     *
158
     * @return boolean TRUE if artefacts are available, else FALSE
159
     */
160
    protected function hasArtefactsByTypeAndEntityId($type, $entityId)
161
    {
162
        return $this->getSubject()->hasArtefactsByTypeAndEntityId($type, $entityId);
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 hasArtefactsByTypeAndEntityId() does only exist in the following implementations of said interface: TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Subjects\ExportableTraitImpl.

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...
163
    }
164
165
    /**
166
     * Return the artefacts for the passed type and entity ID.
167
     *
168
     * @param string $type     The artefact type, e. g. configurable
169
     * @param string $entityId The entity ID to return the artefacts for
170
     *
171
     * @return array The array with the artefacts
172
     * @throws \Exception Is thrown, if no artefacts are available
173
     */
174
    protected function getArtefactsByTypeAndEntityId($type, $entityId)
175
    {
176
        return $this->getSubject()->getArtefactsByTypeAndEntityId($type, $entityId);
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 getArtefactsByTypeAndEntityId() does only exist in the following implementations of said interface: TechDivision\Import\Plugins\ExportableSubjectImpl, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Subjects\ExportableTraitImpl.

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...
177
    }
178
179
    /**
180
     * Create's and return's a new empty artefact entity.
181
     *
182
     * @param array $columns             The array with the column data
183
     * @param array $originalColumnNames The array with a mapping from the old to the new column names
184
     *
185
     * @return array The new artefact entity
186
     */
187
    protected function newArtefact(array $columns, array $originalColumnNames)
188
    {
189
        return $this->getSubject()->newArtefact($columns, $originalColumnNames);
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 newArtefact() does only exist in the following implementations of said interface: TechDivision\Import\Plugins\ExportableSubjectImpl, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Subjects\ExportableTraitImpl.

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...
190
    }
191
192
    /**
193
     * Add the passed product type artefacts to the product with the
194
     * last entity ID.
195
     *
196
     * @param array $artefacts The product type artefacts
197
     *
198
     * @return void
199
     * @uses \TechDivision\Import\Product\Media\Subjects\MediaSubject::getLastEntityId()
200
     */
201
    protected function addArtefacts(array $artefacts)
202
    {
203
        $this->getSubject()->addArtefacts(ProductUrlRewriteObserver::ARTEFACT_TYPE, $artefacts);
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 addArtefacts() does only exist in the following implementations of said interface: TechDivision\Import\Plugins\ExportableSubjectImpl, TechDivision\Import\Product\Subjects\BunchSubject, TechDivision\Import\Subjects\ExportableTraitImpl.

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...
204
    }
205
}
206