Passed
Push — master ( 100000...ac8836 )
by
unknown
01:39 queued 13s
created

VarnishActionManager::getAllProductsUrls()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * File:VarnishActionManager.php
7
 *
8
 * @author Maciej Sławik <[email protected]>
9
 * @author Bartosz Kubicki <[email protected]>
10
 * @copyright Copyright (C) 2019 Lizard Media (http://lizardmedia.pl)
11
 */
12
13
namespace LizardMedia\VarnishWarmer\Model;
14
15
use LizardMedia\VarnishWarmer\Api\Config\PurgingConfigProviderInterface;
16
use LizardMedia\VarnishWarmer\Api\LockHandler\LockInterface;
17
use LizardMedia\VarnishWarmer\Api\QueueHandler\VarnishUrlPurgerInterface;
18
use LizardMedia\VarnishWarmer\Api\QueueHandler\VarnishUrlRegeneratorInterface;
19
use LizardMedia\VarnishWarmer\Api\UrlProvider\CategoryUrlProviderInterface;
20
use LizardMedia\VarnishWarmer\Api\UrlProvider\ProductUrlProviderInterface;
21
use LizardMedia\VarnishWarmer\Api\VarnishActionManagerInterface;
22
use LizardMedia\VarnishWarmer\Model\QueueHandler\VarnishUrlPurgerFactory;
23
use LizardMedia\VarnishWarmer\Model\QueueHandler\VarnishUrlRegeneratorFactory;
24
use Magento\Catalog\Api\Data\ProductInterface;
25
use Magento\Framework\App\Config\ScopeConfigInterface;
26
use Magento\Framework\Exception\NoSuchEntityException;
27
use Magento\Store\Api\Data\StoreInterface;
28
use Magento\Store\Model\ScopeInterface;
29
use Magento\Store\Model\Store;
30
use Magento\Store\Model\StoreManagerInterface;
31
32
/**
33
 * TODO: Refactor, decouple
34
 * Class VarnishActionManager
35
 * @package LizardMedia\VarnishWarmer\Model
36
 * @SuppressWarnings(PHPMD.LongVariable)
37
 */
38
class VarnishActionManager implements VarnishActionManagerInterface
39
{
40
    /**
41
     * @var int
42
     */
43
    private const DEFAULT_FRONTEND_STORE_VIEW_ID = 1;
44
45
    /**
46
     * @var array
47
     */
48
    private $purgeBaseUrls;
49
50
    /**
51
     * @var string
52
     */
53
    private $regenBaseUrl;
54
55
    /**
56
     * @var int
57
     */
58
    private $storeViewId;
59
60
    /**
61
     * @var bool
62
     */
63
    private $isStoreCodeUsedInUrls;
64
65
    /**
66
     * @var StoreInterface
67
     */
68
    private $currentStoreView;
69
70
    /**
71
     * @var VarnishUrlRegeneratorInterface
72
     */
73
    private $varnishUrlRegenerator;
74
75
    /**
76
     * @var VarnishUrlPurgerInterface
77
     */
78
    private $varnishUrlPurger;
79
80
    /**
81
     * @var LockInterface
82
     */
83
    private $lockHandler;
84
85
    /**
86
     * @var ScopeConfigInterface
87
     */
88
    private $scopeConfig;
89
90
    /**
91
     * @var ProductUrlProviderInterface
92
     */
93
    private $productUrlProvider;
94
95
    /**
96
     * @var CategoryUrlProviderInterface
97
     */
98
    private $categoryUrlProvider;
99
100
    /**
101
     * @var PurgingConfigProviderInterface
102
     */
103
    private $purgingConfigProvider;
104
105
    /**
106
     * @var StoreManagerInterface
107
     */
108
    private $storeManager;
109
110
    /**
111
     * VarnishActionManager constructor.
112
     * @param VarnishUrlRegeneratorFactory $varnishUrlRegeneratorFactory
113
     * @param VarnishUrlPurgerFactory $varnishUrlPurgerFactory
114
     * @param LockInterface $lockHandler
115
     * @param ScopeConfigInterface $scopeConfig
116
     * @param ProductUrlProviderInterface $productUrlProvider
117
     * @param CategoryUrlProviderInterface $categoryUrlProvider
118
     * @param PurgingConfigProviderInterface $purgingConfigProvider
119
     * @param StoreManagerInterface $storeManager
120
     * @SuppressWarnings(PHPMD.LongVariable)
121
     * @throws NoSuchEntityException
122
     */
123
    public function __construct(
124
        VarnishUrlRegeneratorFactory $varnishUrlRegeneratorFactory,
125
        VarnishUrlPurgerFactory $varnishUrlPurgerFactory,
126
        LockInterface $lockHandler,
127
        ScopeConfigInterface $scopeConfig,
128
        ProductUrlProviderInterface $productUrlProvider,
129
        CategoryUrlProviderInterface $categoryUrlProvider,
130
        PurgingConfigProviderInterface $purgingConfigProvider,
131
        StoreManagerInterface $storeManager
132
    ) {
133
        $this->lockHandler = $lockHandler;
134
        $this->scopeConfig = $scopeConfig;
135
        $this->productUrlProvider = $productUrlProvider;
136
        $this->categoryUrlProvider = $categoryUrlProvider;
137
        $this->purgingConfigProvider = $purgingConfigProvider;
138
139
        /** @var VarnishUrlRegeneratorInterface varnishUrlRegenerator */
140
        $this->varnishUrlRegenerator = $varnishUrlRegeneratorFactory->create();
141
        /** @var VarnishUrlPurgerInterface varnishUrlPurger */
142
        $this->varnishUrlPurger = $varnishUrlPurgerFactory->create();
143
        $this->storeManager = $storeManager;
144
        $this->storeViewId = $this->getDefaultStoreViewId();
145
        $this->isStoreCodeUsedInUrls = $this->isStoreCodeUsedInUrls();
146
    }
147
148
    /**
149
     * Purge *
150
     * Regen homepage, categories, products
151
     * @return void
152
     * @throws NoSuchEntityException
153
     */
154
    public function purgeWildcard(): void
155
    {
156
        $this->lock();
157
        $this->addUrlToPurge('*');
158
        $this->addUrlToRegenerate('');
159
        $this->regenerateCategories();
160
        $this->processProductsRegenerate();
161
        $this->varnishUrlPurger->purge();
162
        $this->varnishUrlRegenerator->regenerate();
163
        $this->unlock();
164
    }
165
166
    /**
167
     * Purge * without any regeneration
168
     * Pass through lock
169
     * @return void
170
     * @throws NoSuchEntityException
171
     */
172
    public function purgeWildcardWithoutRegen(): void
173
    {
174
        $this->addUrlToPurge('*');
175
        $this->varnishUrlPurger->purge();
176
    }
177
178
    /**
179
     * Purge homepage, categories, products
180
     * Regen homepage, categories, products
181
     * @return void
182
     * @throws NoSuchEntityException
183
     */
184
    public function purgeAll(): void
185
    {
186
        $this->lock();
187
        $this->addUrlToPurge('');
188
        $this->addUrlToRegenerate('');
189
        $this->processCategoriesPurgeAndRegenerate();
190
        $this->processProductsPurgeAndRegenerate();
191
        $this->varnishUrlPurger->purge();
192
        $this->varnishUrlRegenerator->regenerate();
193
        $this->unlock();
194
    }
195
196
    /**
197
     * Purge homepage, categories
198
     * Regen homepage, categories
199
     * @return void
200
     * @throws NoSuchEntityException
201
     */
202
    public function purgeGeneral(): void
203
    {
204
        $this->lock();
205
        $this->addUrlToPurge('');
206
        $this->addUrlToRegenerate('');
207
        $this->processCategoriesPurgeAndRegenerate();
208
        $this->varnishUrlPurger->purge();
209
        $this->varnishUrlRegenerator->regenerate();
210
        $this->unlock();
211
    }
212
213
    /**
214
     * Purge homepage
215
     * Regen homepage
216
     * @return void
217
     * @throws NoSuchEntityException
218
     */
219
    public function purgeHomepage(): void
220
    {
221
        $this->lock();
222
        $this->addUrlToPurge('');
223
        $this->addUrlToRegenerate('');
224
        $this->varnishUrlPurger->purge();
225
        $this->varnishUrlRegenerator->regenerate();
226
        $this->unlock();
227
    }
228
229
    /**
230
     * @return void
231
     * @throws NoSuchEntityException
232
     */
233
    public function purgeAndRegenerateProducts(): void
234
    {
235
        $this->lock();
236
        $this->processProductsPurgeAndRegenerate();
237
        $this->varnishUrlPurger->purge();
238
        $this->varnishUrlRegenerator->regenerate();
239
        $this->unlock();
240
    }
241
242
    /**
243
     * @param string $url
244
     * @return void
245
     * @throws NoSuchEntityException
246
     */
247
    public function purgeAndRegenerateUrl(string $url): void
248
    {
249
        $this->addUrlToPurge($url);
250
        $this->addUrlToRegenerate($url);
251
        $this->varnishUrlPurger->purge();
252
        $this->varnishUrlRegenerator->regenerate();
253
    }
254
255
    /**
256
     * @param ProductInterface $product
257
     * @return void
258
     * @throws NoSuchEntityException
259
     */
260
    public function purgeProduct(ProductInterface $product): void
261
    {
262
        $productUrls = $this->getProductUrls((int) $product->getId());
263
264
        foreach ($productUrls as $url) {
265
            $this->addUrlToPurge($url['request_path'], true);
266
        }
267
268
        $this->varnishUrlPurger->purge();
269
        $this->varnishUrlRegenerator->regenerate();
270
    }
271
272
    /**
273
     * @param int $storeViewId
274
     */
275
    public function setStoreViewId(int $storeViewId): void
276
    {
277
        $this->storeViewId = $storeViewId;
278
    }
279
280
    /**
281
     * @return bool
282
     */
283
    public function isLocked(): bool
284
    {
285
        return $this->lockHandler->isLocked();
286
    }
287
288
    /**
289
     * @return string
290
     */
291
    public function getLockMessage(): string
292
    {
293
        return $this->lockHandler->getLockDate();
294
    }
295
296
    /**
297
     * @return int
298
     * @throws NoSuchEntityException
299
     */
300
    private function getDefaultStoreViewId(): int
301
    {
302
        $defaultStoreView = $this->storeManager->getStore(self::DEFAULT_FRONTEND_STORE_VIEW_ID);
303
        return $defaultStoreView instanceof StoreInterface
0 ignored issues
show
Bug introduced by
The class Magento\Store\Api\Data\StoreInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
304
            ? (int) $defaultStoreView->getId()
305
            : 1;
306
    }
307
308
    /**
309
     * @return bool
310
     */
311
    private function isStoreCodeUsedInUrls(): bool
312
    {
313
        if (empty($this->isStoreCodeUsedInUrls)) {
314
            $this->isStoreCodeUsedInUrls = $this->scopeConfig->isSetFlag(Store::XML_PATH_STORE_IN_URL);
315
        }
316
317
        return $this->isStoreCodeUsedInUrls;
318
    }
319
320
    /**
321
     * @param $relativeUrl
322
     * @param bool $autoRegenerate
323
     * @return void
324
     * @throws NoSuchEntityException
325
     */
326
    private function addUrlToPurge(string $relativeUrl, bool $autoRegenerate = false): void
327
    {
328
        foreach ($this->getPurgeBaseUrls() as $purgeBaseUrl) {
329
            $url = $purgeBaseUrl . $this->buildStoreCodePartIfUsed() .  $relativeUrl;
330
            $this->varnishUrlPurger->addUrlToPurge($url);
331
332
            if ($autoRegenerate) {
333
                $this->addUrlToRegenerate($relativeUrl);
334
            }
335
        }
336
    }
337
338
    /**
339
     * @param string $relativeUrl
340
     * @return void
341
     * @throws NoSuchEntityException
342
     */
343
    private function addUrlToRegenerate(string $relativeUrl): void
344
    {
345
        $url = $this->getRegenBaseUrl() . $this->buildStoreCodePartIfUsed() . $relativeUrl;
346
        $this->varnishUrlRegenerator->addUrlToRegenerate($url);
347
    }
348
349
    /**
350
     * @return string
351
     * @throws NoSuchEntityException
352
     */
353
    private function buildStoreCodePartIfUsed(): string
354
    {
355
        if ($this->isStoreCodeUsedInUrls) {
356
            return sprintf('%s/', $this->getStoreCode());
357
        }
358
359
        return '';
360
    }
361
362
    /**
363
     * @return string
364
     * @throws NoSuchEntityException
365
     */
366
    private function getStoreCode(): string
367
    {
368
        $currentStore = $this->getCurrentStoreView();
369
        return $currentStore->getCode();
370
    }
371
372
    /**
373
     * @return StoreInterface
374
     * @throws NoSuchEntityException
375
     */
376
    private function getCurrentStoreView(): StoreInterface
377
    {
378
        if (!$this->currentStoreView instanceof StoreInterface) {
0 ignored issues
show
Bug introduced by
The class Magento\Store\Api\Data\StoreInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
379
            $this->currentStoreView = $this->storeManager->getStore($this->storeViewId);
380
        }
381
382
        return $this->currentStoreView;
383
    }
384
385
    /**
386
     * @return void
387
     * @throws NoSuchEntityException
388
     */
389
    private function regenerateCategories(): void
390
    {
391
        $categories = $this->getCategories();
392
393
        foreach ($categories as $category) {
394
            $this->addUrlToRegenerate($category['request_path']);
395
        }
396
    }
397
398
    /**
399
     * @return void
400
     * @throws NoSuchEntityException
401
     */
402
    private function processCategoriesPurgeAndRegenerate(): void
403
    {
404
        $categories = $this->getCategories();
405
406
        foreach ($categories as $category) {
407
            $this->addUrlToPurge($category['request_path'], true);
408
        }
409
    }
410
411
    /**
412
     * @return void
413
     * @throws NoSuchEntityException
414
     */
415
    private function processProductsRegenerate(): void
416
    {
417
        $productUrls = $this->getAllProductsUrls();
418
419
        foreach ($productUrls as $url) {
420
            $this->addUrlToRegenerate($url['request_path']);
421
        }
422
    }
423
424
    /**
425
     * @return void
426
     * @throws NoSuchEntityException
427
     */
428
    private function processProductsPurgeAndRegenerate(): void
429
    {
430
        $productUrls = $this->getAllProductsUrls();
431
432
        foreach ($productUrls as $url) {
433
            $this->addUrlToPurge($url['request_path'], true);
434
        }
435
    }
436
437
    /**
438
     * @return array
439
     */
440
    private function getAllProductsUrls(): array
441
    {
442
        return $this->productUrlProvider->getActiveProductsUrls();
443
    }
444
445
    /**
446
     * @param $productId
447
     * @return array
448
     */
449
    private function getProductUrls(int $productId): array
450
    {
451
        return $this->productUrlProvider->getProductUrls($productId);
452
    }
453
454
    /**
455
     * @return array
456
     */
457
    private function getCategories(): array
458
    {
459
        return $this->categoryUrlProvider->getActiveCategoriesUrls();
460
    }
461
462
    /**
463
     * @return void
464
     */
465
    private function lock(): void
466
    {
467
        $this->lockHandler->lock();
468
    }
469
470
    /**
471
     * @return void
472
     */
473
    private function unlock(): void
474
    {
475
        $this->lockHandler->unlock();
476
    }
477
478
    /**
479
     * @return void
480
     */
481
    private function setPurgeBaseUrls(): void
482
    {
483
        if ($this->purgingConfigProvider->isPurgeCustomHostEnabled()) {
484
            $this->purgeBaseUrls = $this->purgingConfigProvider->getCustomPurgeHosts();
485
        } else {
486
            $baseUrl = $this->scopeConfig->getValue(
487
                Store::XML_PATH_SECURE_BASE_URL,
488
                ScopeInterface::SCOPE_STORE,
489
                $this->storeViewId
490
            );
491
            $this->purgeBaseUrls = [$baseUrl];
492
        }
493
494
        foreach ($this->purgeBaseUrls as &$purgeBaseUrl) {
495
            if (substr($purgeBaseUrl, -1) !== '/') {
496
                $purgeBaseUrl .= '/';
497
            }
498
        }
499
    }
500
501
    /**
502
     * @return void
503
     */
504
    private function setRegenBaseUrl(): void
505
    {
506
        $this->regenBaseUrl = (string) $this->scopeConfig->getValue(
507
            Store::XML_PATH_SECURE_BASE_URL,
508
            ScopeInterface::SCOPE_STORE,
509
            $this->storeViewId
510
        );
511
512
        if (substr($this->regenBaseUrl, -1) !== '/') {
513
            $this->regenBaseUrl .= '/';
514
        }
515
    }
516
517
    /**
518
     * @return array
519
     */
520
    private function getPurgeBaseUrls(): array
521
    {
522
        if (!$this->purgeBaseUrls) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->purgeBaseUrls of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
523
            $this->setPurgeBaseUrls();
524
        }
525
526
        return $this->purgeBaseUrls;
527
    }
528
529
    /**
530
     * @return string
531
     */
532
    private function getRegenBaseUrl(): string
533
    {
534
        if (!$this->regenBaseUrl) {
535
            $this->setRegenBaseUrl();
536
        }
537
538
        return $this->regenBaseUrl;
539
    }
540
}
541