Completed
Pull Request — master (#37)
by Tim
01:49
created

UrlRewriteObserver::prepareUrlRewrites()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * TechDivision\Import\Category\Observers\UrlRewriteObserver
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-category
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Category\Observers;
22
23
use TechDivision\Import\Category\Utils\ColumnKeys;
24
use TechDivision\Import\Category\Utils\MemberNames;
25
use TechDivision\Import\Category\Utils\CoreConfigDataKeys;
26
use TechDivision\Import\Category\Services\CategoryBunchProcessorInterface;
27
28
/**
29
 * Observer that creates/updates the category's URL rewrites.
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-category
35
 * @link      http://www.techdivision.com
36
 */
37
class UrlRewriteObserver extends AbstractCategoryImportObserver
38
{
39
40
    /**
41
     * The entity type to load the URL rewrites for.
42
     *
43
     * @var string
44
     */
45
    const ENTITY_TYPE = 'category';
46
47
    /**
48
     * The processor to read/write the necessary category data.
49
     *
50
     * @var \TechDivision\Import\Category\Services\CategoryBunchProcessorInterface
51
     */
52
    protected $categoryBunchProcessor;
53
54
    /**
55
     * Initialize the subject instance.
56
     *
57
     * @param \TechDivision\Import\Category\Services\CategoryBunchProcessorInterface $categoryBunchProcessor The category bunch processor instance
58
     */
59
    public function __construct(CategoryBunchProcessorInterface $categoryBunchProcessor)
60
    {
61
        $this->categoryBunchProcessor = $categoryBunchProcessor;
62
    }
63
64
    /**
65
     * Return's the category bunch processor instance.
66
     *
67
     * @return \TechDivision\Import\Category\Services\CategoryBunchProcessorInterface The category bunch processor instance
68
     */
69
    protected function getCategoryBunchProcessor()
70
    {
71
        return $this->categoryBunchProcessor;
72
    }
73
74
    /**
75
     * Process the observer's business logic.
76
     *
77
     * @return void
78
     */
79
    protected function process()
80
    {
81
82
        // try to load the entity ID for the product with the passed SKU
83
        if ($category = $this->getSubject()->getCategoryByPath($path = $this->getValue(ColumnKeys::PATH))) {
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 getCategoryByPath() does only exist in the following implementations of said interface: TechDivision\Import\Cate...AbstractCategorySubject, TechDivision\Import\Category\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...
84
            $this->setLastEntityId($category[MemberNames::ENTITY_ID]);
85
        } else {
86
            // prepare a log message
87
            $message = sprintf('Category with path "%s" can\'t be loaded to create URL rewrites', $path);
88
            // query whether or not we're in debug mode
89
            if ($this->getSubject()->isDebugMode()) {
90
                $this->getSubject()->getSystemLogger()->warning($message);
91
                return;
92
            } else {
93
                throw new \Exception($message);
94
            }
95
        }
96
97
        // initialize the store view code
98
        $this->getSubject()->prepareStoreViewCode();
99
100
        // prepare the URL rewrites
101
        $this->prepareUrlRewrites();
102
103
        // initialize and persist the URL rewrite
104
        if ($urlRewrite = $this->initializeUrlRewrite($this->prepareAttributes())) {
105
            $this->persistUrlRewrite($urlRewrite);
106
        }
107
    }
108
109
    /**
110
     * Initialize the URL rewrite with the passed attributes and returns an instance.
111
     *
112
     * @param array $attr The URL rewrite attributes
113
     *
114
     * @return array The initialized URL rewrite
115
     */
116
    protected function initializeUrlRewrite(array $attr)
117
    {
118
        return $attr;
119
    }
120
121
    /**
122
     * Prepare's the URL rewrites that has to be created/updated.
123
     *
124
     * @return void
125
     */
126
    protected function prepareUrlRewrites()
127
    {
128
        // nothing to prepare here
129
    }
130
131
    /**
132
     * Prepare the attributes of the entity that has to be persisted.
133
     *
134
     * @return array The prepared attributes
135
     */
136
    protected function prepareAttributes()
137
    {
138
139
        // load the store ID to use
140
        $storeId = $this->getRowStoreId();
141
142
        // initialize the values
143
        $entityId = $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\Cate...AbstractCategorySubject, TechDivision\Import\Category\Subjects\BunchSubject, TechDivision\Import\Observers\EntitySubjectImpl, TechDivision\Import\Plugins\ExportableSubjectImpl, 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...
144
        $requestPath = $this->prepareRequestPath();
145
        $targetPath = $this->prepareTargetPath();
146
147
        // return the prepared URL rewrite
148
        return $this->initializeEntity(
149
            array(
150
                MemberNames::ENTITY_TYPE      => UrlRewriteObserver::ENTITY_TYPE,
151
                MemberNames::ENTITY_ID        => $entityId,
152
                MemberNames::REQUEST_PATH     => $requestPath,
153
                MemberNames::TARGET_PATH      => $targetPath,
154
                MemberNames::REDIRECT_TYPE    => 0,
155
                MemberNames::STORE_ID         => $storeId,
156
                MemberNames::DESCRIPTION      => null,
157
                MemberNames::IS_AUTOGENERATED => 1,
158
                MemberNames::METADATA         => null
159
            )
160
        );
161
    }
162
163
    /**
164
     * Prepare's the target path for a URL rewrite.
165
     *
166
     * @return string The target path
167
     */
168
    protected function prepareTargetPath()
169
    {
170
        return sprintf('catalog/category/view/id/%d', $this->getPrimaryKey());
171
    }
172
173
    /**
174
     * Prepare's the request path for a URL rewrite or the target path for a 301 redirect.
175
     *
176
     * @return string The request path
177
     */
178
    protected function prepareRequestPath()
179
    {
180
181
        // load the category URL suffix to use
182
        $urlSuffix = $this->getSubject()->getCoreConfigData(CoreConfigDataKeys::CATALOG_SEO_CATEGORY_URL_SUFFIX, '.html');
183
184
        // prepare and return the category URL
185
        return sprintf('%s%s', $this->getValue(ColumnKeys::URL_PATH), $urlSuffix);
186
    }
187
188
    /**
189
     * Set's the ID of the product that has been created recently.
190
     *
191
     * @param string $lastEntityId The entity ID
192
     *
193
     * @return void
194
     */
195
    protected function setLastEntityId($lastEntityId)
196
    {
197
        $this->getSubject()->setLastEntityId($lastEntityId);
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 setLastEntityId() does only exist in the following implementations of said interface: TechDivision\Import\Cate...AbstractCategorySubject, TechDivision\Import\Category\Subjects\BunchSubject, TechDivision\Import\Plugins\ExportableSubjectImpl, 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...
198
    }
199
200
    /**
201
     * Return's the store ID of the actual row, or of the default store
202
     * if no store view code is set in the CSV file.
203
     *
204
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
205
     *
206
     * @return integer The ID of the actual store
207
     * @throws \Exception Is thrown, if the store with the actual code is not available
208
     */
209
    protected function getRowStoreId($default = null)
210
    {
211
        return $this->getSubject()->getRowStoreId($default);
0 ignored issues
show
Bug introduced by
The method getRowStoreId() does not exist on TechDivision\Import\Subjects\SubjectInterface. Did you maybe mean getRow()?

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...
212
    }
213
214
    /**
215
     * Persist's the URL rewrite with the passed data.
216
     *
217
     * @param array $row The URL rewrite to persist
218
     *
219
     * @return string The ID of the persisted entity
220
     */
221
    protected function persistUrlRewrite($row)
222
    {
223
        return $this->getCategoryBunchProcessor()->persistUrlRewrite($row);
224
    }
225
226
    /**
227
     * Return's the PK to create the product => attribute relation.
228
     *
229
     * @return integer The PK to create the relation with
230
     */
231
    protected function getPrimaryKey()
232
    {
233
        return $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\Cate...AbstractCategorySubject, TechDivision\Import\Category\Subjects\BunchSubject, TechDivision\Import\Observers\EntitySubjectImpl, TechDivision\Import\Plugins\ExportableSubjectImpl, 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...
234
    }
235
}
236