Completed
Pull Request — master (#17)
by Tim
03:38
created

UrlRewriteObserver::prepareUrlKey()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 35
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 8.125

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 8
cts 16
cp 0.5
rs 8.439
c 0
b 0
f 0
cc 5
eloc 13
nc 10
nop 0
crap 8.125
1
<?php
2
3
/**
4
 * TechDivision\Import\Product\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-product
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Product\Observers;
22
23
use TechDivision\Import\Product\Utils\ColumnKeys;
24
use TechDivision\Import\Product\Utils\MemberNames;
25
use TechDivision\Import\Product\Utils\Filter\ConvertLiteralUrl;
26
use TechDivision\Import\Product\Observers\AbstractProductImportObserver;
27
28
/**
29
 * Observer that creates/updates the product'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-product
35
 * @link      http://www.techdivision.com
36
 */
37
class UrlRewriteObserver extends AbstractProductImportObserver
38
{
39
40
    /**
41
     * The entity type to load the URL rewrites for.
42
     *
43
     * @var string
44
     */
45
    const ENTITY_TYPE = 'product';
46
47
    /**
48
     * The URL key from the CSV file column that has to be processed by the observer.
49
     *
50
     * @var string
51
     */
52
    protected $urlKey;
53
54
    /**
55
     * The actual category ID to process.
56
     *
57
     * @var integer
58
     */
59
    protected $categoryId;
60
61
    /**
62
     * The actual entity ID to process.
63
     *
64
     * @var integer
65
     */
66
    protected $entityId;
67
68
    /**
69
     * The array with the URL rewrites that has to be created.
70
     *
71
     * @var array
72
     */
73
    protected $urlRewrites = array();
74
75
    /**
76
     * Will be invoked by the action on the events the listener has been registered for.
77
     *
78
     * @param array $row The row to handle
79
     *
80
     * @return array The modified row
81
     * @see \TechDivision\Import\Product\Observers\ImportObserverInterface::handle()
82
     */
83 3 View Code Duplication
    public function handle(array $row)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
    {
85
86
        // initialize the row
87 3
        $this->setRow($row);
88
89
        // query whether or not, we've found a new SKU => means we've found a new product
90 3
        if ($this->isLastSku($this->getValue(ColumnKeys::SKU))) {
91
            return $this->getRow();
92
        }
93
94
        // process the functionality and return the row
95 3
        $this->process();
96
97
        // return the processed row
98 3
        return $this->getRow();
99
    }
100
101
    /**
102
     * Set's the prepared URL key.
103
     *
104
     * @param string $urlKey The prepared URL key
105
     *
106
     * @return void
107
     */
108 3
    protected function setUrlKey($urlKey)
109
    {
110 3
        $this->urlKey = $urlKey;
111 3
    }
112
113
    /**
114
     * Return's the prepared URL key.
115
     *
116
     * @return string The prepared URL key
117
     */
118 3
    protected function getUrlKey()
119
    {
120 3
        return $this->urlKey;
121
    }
122
123
    /**
124
     * Set's the actual category ID to process.
125
     *
126
     * @param integer $categoryId The category ID
127
     *
128
     * @return void
129
     */
130 3
    protected function setCategoryId($categoryId)
131
    {
132 3
        $this->categoryId = $categoryId;
133 3
    }
134
135
    /**
136
     * Return's the actual category ID to process.
137
     *
138
     * @return integer The category ID
139
     */
140 3
    protected function getCategoryId()
141
    {
142 3
        return $this->categoryId;
143
    }
144
145
    /**
146
     * Set's the actual entity ID to process.
147
     *
148
     * @param integer $entityId The entity ID
149
     *
150
     * @return void
151
     */
152 3
    protected function setEntityId($entityId)
153
    {
154 3
        $this->entityId = $entityId;
155 3
    }
156
157
    /**
158
     * Return's the actual entity ID to process.
159
     *
160
     * @return integer The entity ID
161
     */
162 3
    protected function getEntityId()
163
    {
164 3
        return $this->entityId;
165
    }
166
167
    /**
168
     * Process the observer's business logic.
169
     *
170
     * @return void
171
     */
172 3
    protected function process()
173
    {
174
175
        // try to prepare the URL key, return immediately if not possible
176 3
        if (!$this->prepareUrlKey()) {
177
            return;
178
        }
179
180
        // initialize the store view code
181 3
        $this->prepareStoreViewCode();
182
183
        // prepare the URL rewrites
184 3
        $this->prepareUrlRewrites();
185
186
        // iterate over the categories and create the URL rewrites
187 3
        foreach ($this->urlRewrites as $urlRewrite) {
188
            // initialize and persist the URL rewrite
189 3
            if ($urlRewrite = $this->initializeUrlRewrite($urlRewrite)) {
190 3
                $this->persistUrlRewrite($urlRewrite);
191 3
            }
192 3
        }
193 3
    }
194
195
    /**
196
     * Initialize the category product with the passed attributes and returns an instance.
197
     *
198
     * @param array $attr The category product attributes
199
     *
200
     * @return array The initialized category product
201
     */
202 2
    protected function initializeUrlRewrite(array $attr)
203
    {
204 2
        return $attr;
205
    }
206
207
    /**
208
     * Prepare's the URL rewrites that has to be created/updated.
209
     *
210
     * @return void
211
     */
212 3
    protected function prepareUrlRewrites()
213
    {
214
215
        // (re-)initialize the array for the URL rewrites
216 3
        $this->urlRewrites = array();
217
218
        // load the root category, because we need that to create the default product URL rewrite
219 3
        $rootCategory = $this->getRootCategory();
220
221
        // add the root category ID to the category => product relations
222 3
        $productCategoryIds = $this->getProductCategoryIds();
223 3
        $productCategoryIds[$rootCategory[MemberNames::ENTITY_ID]] = $this->getLastEntityId();
224
225
        // prepare the URL rewrites
226 3
        foreach ($productCategoryIds as $categoryId => $entityId) {
227
            // set category/entity ID
228 3
            $this->setCategoryId($categoryId);
229 3
            $this->setEntityId($entityId);
230
231
            // prepare the attributes for each URL rewrite
232 3
            $this->urlRewrites[$categoryId] = $this->prepareAttributes();
233 3
        }
234 3
    }
235
236
    /**
237
     * Prepare's and set's the URL key from the passed row of the CSV file.
238
     *
239
     * @return boolean TRUE, if the URL key has been prepared, else FALSE
240
     */
241 3
    protected function prepareUrlKey()
242
    {
243
244
        // initialize the URL key
245 3
        $urlKey = null;
246
247
        // query whether or not we've a URL key available in the CSV file row
248 3
        if ($urlKeyFound = $this->getValue(ColumnKeys::URL_KEY)) {
249 3
            $urlKey = $urlKeyFound;
250 3
        }
251
252
        // query whether or not an URL key has been specified in the CSV file
253 3
        if (empty($urlKey)) {
254
            // initialize the product name
255
            $productName = null;
256
            // if not, try to use the product name
257
            if ($nameFound = $this->getValue(ColumnKeys::NAME)) {
258
                $productName = $nameFound;
259
            }
260
261
            // if nor URL key AND product name are empty, return immediately
262
            if (empty($productName)) {
263
                return false;
264
            }
265
266
            // initialize the URL key with product name
267
            $urlKey = $this->convertNameToUrlKey($productName);
268
        }
269
270
        // convert and set the URL key
271 3
        $this->setUrlKey($urlKey);
272
273
        // return TRUE if the URL key has been prepared
274 3
        return true;
275
    }
276
277
    /**
278
     * Prepare the attributes of the entity that has to be persisted.
279
     *
280
     * @return array The prepared attributes
281
     */
282 3
    protected function prepareAttributes()
283
    {
284
285
        // load entity/category ID
286 3
        $entityId = $this->getEntityId();
287 3
        $categoryId = $this->getCategoryId();
288
289
        // load the store ID to use
290 3
        $storeId = $this->getRowStoreId();
291
292
        // load the category to create the URL rewrite for
293 3
        $category = $this->getCategory($categoryId);
294
295
        // initialize the values
296 3
        $requestPath = $this->prepareRequestPath($category);
297 3
        $targetPath = $this->prepareTargetPath($category);
298 3
        $metadata = serialize($this->prepareMetadata($category));
299
300
        // return the prepared URL rewrite
301 3
        return $this->initializeEntity(
302
            array(
303 3
                MemberNames::ENTITY_TYPE      => UrlRewriteObserver::ENTITY_TYPE,
304 3
                MemberNames::ENTITY_ID        => $entityId,
305 3
                MemberNames::REQUEST_PATH     => $requestPath,
306 3
                MemberNames::TARGET_PATH      => $targetPath,
307 3
                MemberNames::REDIRECT_TYPE    => 0,
308 3
                MemberNames::STORE_ID         => $storeId,
309 3
                MemberNames::DESCRIPTION      => null,
310 3
                MemberNames::IS_AUTOGENERATED => 1,
311 3
                MemberNames::METADATA         => $metadata
312 3
            )
313 3
        );
314
    }
315
316
    /**
317
     * Prepare's the target path for a URL rewrite.
318
     *
319
     * @param array $category The categroy with the URL path
320
     *
321
     * @return string The target path
322
     */
323 3
    protected function prepareTargetPath(array $category)
324
    {
325
326
        // load the actual entity ID
327 3
        $lastEntityId = $this->getPrimaryKey();
328
329
        // query whether or not, the category is the root category
330 3
        if ($this->isRootCategory($category)) {
331 3
            $targetPath = sprintf('catalog/product/view/id/%d', $lastEntityId);
332 3
        } else {
333 2
            $targetPath = sprintf('catalog/product/view/id/%d/category/%d', $lastEntityId, $category[MemberNames::ENTITY_ID]);
334
        }
335
336
        // return the target path
337 3
        return $targetPath;
338
    }
339
340
    /**
341
     * Prepare's the request path for a URL rewrite or the target path for a 301 redirect.
342
     *
343
     * @param array $category The categroy with the URL path
344
     *
345
     * @return string The request path
346
     */
347 3
    protected function prepareRequestPath(array $category)
348
    {
349
350
        // query whether or not, the category is the root category
351 3
        if ($this->isRootCategory($category)) {
352 3
            $requestPath = sprintf('%s.html', $this->getUrlKey());
353 3
        } else {
354 2
            $requestPath = sprintf('%s/%s.html', $category[MemberNames::URL_PATH], $this->getUrlKey());
355
        }
356
357
        // return the request path
358 3
        return $requestPath;
359
    }
360
361
    /**
362
     * Prepare's the URL rewrite's metadata with the passed category values.
363
     *
364
     * @param array $category The category used for preparation
365
     *
366
     * @return array The metadata
367
     */
368 3
    protected function prepareMetadata(array $category)
369
    {
370
371
        // initialize the metadata
372 3
        $metadata = array();
373
374
        // query whether or not, the passed category IS the root category
375 3
        if ($this->isRootCategory($category)) {
376 3
            return $metadata;
377
        }
378
379
        // if not, set the category ID in the metadata
380 2
        $metadata['category_id'] = $category[MemberNames::ENTITY_ID];
381
382
        // return the metadata
383 2
        return $metadata;
384
    }
385
386
    /**
387
     * Initialize's and return's the URL key filter.
388
     *
389
     * @return \TechDivision\Import\Product\Utils\ConvertLiteralUrl The URL key filter
390
     */
391
    protected function getUrlKeyFilter()
392
    {
393
        return new ConvertLiteralUrl();
394
    }
395
396
    /**
397
     * Convert's the passed string into a valid URL key.
398
     *
399
     * @param string $string The string to be converted, e. g. the product name
400
     *
401
     * @return string The converted string as valid URL key
402
     */
403
    protected function convertNameToUrlKey($string)
404
    {
405
        return $this->getUrlKeyFilter()->filter($string);
406
    }
407
408
    /**
409
     * Return's the root category for the actual view store.
410
     *
411
     * @return array The store's root category
412
     * @throws \Exception Is thrown if the root category for the passed store code is NOT available
413
     */
414 3
    protected function getRootCategory()
415
    {
416 3
        return $this->getSubject()->getRootCategory();
417
    }
418
419
    /**
420
     * Return's TRUE if the passed category IS the root category, else FALSE.
421
     *
422
     * @param array $category The category to query
423
     *
424
     * @return boolean TRUE if the passed category IS the root category
425
     */
426 3
    protected function isRootCategory(array $category)
427
    {
428
429
        // load the root category
430 3
        $rootCategory = $this->getRootCategory();
431
432
        // compare the entity IDs and return the result
433 3
        return $rootCategory[MemberNames::ENTITY_ID] === $category[MemberNames::ENTITY_ID];
434
    }
435
436
    /**
437
     * Return's the store ID of the actual row, or of the default store
438
     * if no store view code is set in the CSV file.
439
     *
440
     * @param string|null $default The default store view code to use, if no store view code is set in the CSV file
441
     *
442
     * @return integer The ID of the actual store
443
     * @throws \Exception Is thrown, if the store with the actual code is not available
444
     */
445 3
    protected function getRowStoreId($default = null)
446
    {
447 3
        return $this->getSubject()->getRowStoreId($default);
448
    }
449
450
    /**
451
     * Return's the list with category IDs the product is related with.
452
     *
453
     * @return array The product's category IDs
454
     */
455 3
    protected function getProductCategoryIds()
456
    {
457 3
        return $this->getSubject()->getProductCategoryIds();
458
    }
459
460
    /**
461
     * Return's the category with the passed ID.
462
     *
463
     * @param integer $categoryId The ID of the category to return
464
     *
465
     * @return array The category data
466
     */
467 3
    protected function getCategory($categoryId)
468
    {
469 3
        return $this->getSubject()->getCategory($categoryId);
470
    }
471
472
    /**
473
     * Persist's the URL write with the passed data.
474
     *
475
     * @param array $row The URL rewrite to persist
476
     *
477
     * @return void
478
     */
479 3
    protected function persistUrlRewrite($row)
480
    {
481 3
        $this->getSubject()->persistUrlRewrite($row);
482 3
    }
483
484
    /**
485
     * Return's the PK to create the product => attribute relation.
486
     *
487
     * @return integer The PK to create the relation with
488
     */
489 3
    protected function getPrimaryKey()
490
    {
491 3
        return $this->getLastEntityId();
492
    }
493
}
494