ProductAbstractPagePublisher   F
last analyzed

Complexity

Total Complexity 80

Size/Duplication

Total Lines 833
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 255
dl 0
loc 833
rs 2
c 0
b 0
f 0
wmc 80

34 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 1
A publishEntities() 0 41 5
A deleteProductAbstractPageSearchEntities() 0 4 2
A unpublish() 0 5 1
A refresh() 0 15 3
A publish() 0 9 2
A executeProductPageSearchCollectionFilterPlugins() 0 7 2
A expandPageSearchTransferWithPlugins() 0 7 2
A refreshProductPageSearchTransfer() 0 4 1
A assertPageDataExpanderPluginName() 0 4 2
A isSearchable() 0 9 4
A hydrateProductAbstractLocalizedEntitiesWithProductAbstractAddToCartSku() 0 21 4
A findProductAbstractPageSearchEntities() 0 3 1
A findProductAbstractLocalizedEntities() 0 19 3
A mapProductAbstractPageSearchEntities() 0 8 2
A getProductSearchEntitiesByProductConcreteIdsAndLocaleIsoCodes() 0 6 1
A hydrateProductAbstractLocalizedEntitiesWithProductCategories() 0 15 3
A storeData() 0 57 5
A deleteProductAbstractPageSearchEntity() 0 4 2
A pairProductAbstractLocalizedEntityWithProductAbstractPageSearchEntityByStoresAndLocale() 0 27 2
A getProductCategoriesByProductAbstractIds() 0 3 1
A pairRemainingProductAbstractPageSearchEntities() 0 12 1
A isActual() 0 9 4
A pairProductAbstractLocalizedEntitiesWithProductAbstractPageSearchEntities() 0 24 2
A mapPairedEntitiesToProductPageSearchTransfers() 0 24 3
A getProductPageSearchTransfersIndexedByLocaleAndIdProductAbstract() 0 10 2
A getPageDataExpanderPlugins() 0 14 3
A hydrateProductAbstractLocalizedEntitiesWithProductConcreteEntities() 0 15 3
A storeProductAbstractPageSearchEntity() 0 16 1
A getProductConcreteEntitiesWithProductSearchEntities() 0 7 1
A getProductConcreteEntitiesByProductAbstractIdsAndLocaleIsoCodes() 0 6 1
A hydrateProductConcreteEntitiesWithProductSearchEntities() 0 14 3
A findProductPageSearchTransferFromIndexedList() 0 18 4
A getProductPageSearchTransfer() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like ProductAbstractPagePublisher often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ProductAbstractPagePublisher, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\ProductPageSearch\Business\Publisher;
9
10
use Generated\Shared\Transfer\ProductPageLoadTransfer;
11
use Generated\Shared\Transfer\ProductPageSearchTransfer;
12
use Generated\Shared\Transfer\ProductPayloadTransfer;
13
use Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch;
14
use Spryker\Shared\ProductPageSearch\ProductPageSearchConfig as SharedProductPageSearchConfig;
15
use Spryker\Zed\Kernel\Persistence\EntityManager\InstancePoolingTrait;
16
use Spryker\Zed\ProductPageSearch\Business\Exception\PluginNotFoundException;
17
use Spryker\Zed\ProductPageSearch\Business\Mapper\ProductPageSearchMapperInterface;
18
use Spryker\Zed\ProductPageSearch\Business\Model\ProductPageSearchWriterInterface;
19
use Spryker\Zed\ProductPageSearch\Business\Reader\AddToCartSkuReaderInterface;
20
use Spryker\Zed\ProductPageSearch\Dependency\Facade\ProductPageSearchToStoreFacadeInterface;
21
use Spryker\Zed\ProductPageSearch\Persistence\ProductPageSearchQueryContainerInterface;
22
use Spryker\Zed\ProductPageSearch\ProductPageSearchConfig;
23
24
class ProductAbstractPagePublisher implements ProductAbstractPagePublisherInterface
25
{
26
    use InstancePoolingTrait;
27
28
    /**
29
     * @var string
30
     */
31
    public const PRODUCT_ABSTRACT_LOCALIZED_ENTITY = 'PRODUCT_ABSTRACT_LOCALIZED_ENTITY';
32
33
    /**
34
     * @var string
35
     */
36
    public const PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY = 'PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY';
37
38
    /**
39
     * @var string
40
     */
41
    public const STORE_NAME = 'STORE_NAME';
42
43
    /**
44
     * @var string
45
     */
46
    public const LOCALE_NAME = 'LOCALE_NAME';
47
48
    /**
49
     * @var \Spryker\Zed\ProductPageSearch\Persistence\ProductPageSearchQueryContainerInterface
50
     */
51
    protected $queryContainer;
52
53
    /**
54
     * @var array<\Spryker\Zed\ProductPageSearchExtension\Dependency\Plugin\ProductPageDataLoaderPluginInterface>
55
     */
56
    protected $productPageDataLoaderPlugins = [];
57
58
    /**
59
     * @var array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface>
60
     */
61
    protected $pageDataExpanderPlugins = [];
62
63
    /**
64
     * @var array<\Spryker\Zed\ProductPageSearchExtension\Dependency\Plugin\ProductPageSearchCollectionFilterPluginInterface>
65
     */
66
    protected $productPageSearchCollectionFilterPlugins = [];
67
68
    /**
69
     * @var \Spryker\Zed\ProductPageSearch\Business\Mapper\ProductPageSearchMapperInterface
70
     */
71
    protected $productPageSearchMapper;
72
73
    /**
74
     * @var \Spryker\Zed\ProductPageSearch\Business\Model\ProductPageSearchWriterInterface
75
     */
76
    protected $productPageSearchWriter;
77
78
    /**
79
     * @var \Spryker\Zed\ProductPageSearch\Dependency\Facade\ProductPageSearchToStoreFacadeInterface
80
     */
81
    protected $storeFacade;
82
83
    /**
84
     * @var \Spryker\Zed\ProductPageSearch\ProductPageSearchConfig
85
     */
86
    protected $productPageSearchConfig;
87
88
    /**
89
     * @var \Spryker\Zed\ProductPageSearch\Business\Reader\AddToCartSkuReaderInterface
90
     */
91
    protected $addToCartSkuReader;
92
93
    /**
94
     * @param \Spryker\Zed\ProductPageSearch\Persistence\ProductPageSearchQueryContainerInterface $queryContainer
95
     * @param array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface> $pageDataExpanderPlugins
96
     * @param array<\Spryker\Zed\ProductPageSearchExtension\Dependency\Plugin\ProductPageDataLoaderPluginInterface> $productPageDataLoaderPlugins
97
     * @param array<\Spryker\Zed\ProductPageSearchExtension\Dependency\Plugin\ProductPageSearchCollectionFilterPluginInterface> $productPageSearchCollectionFilterPlugins
98
     * @param \Spryker\Zed\ProductPageSearch\Business\Mapper\ProductPageSearchMapperInterface $productPageSearchMapper
99
     * @param \Spryker\Zed\ProductPageSearch\Business\Model\ProductPageSearchWriterInterface $productPageSearchWriter
100
     * @param \Spryker\Zed\ProductPageSearch\ProductPageSearchConfig $productPageSearchConfig
101
     * @param \Spryker\Zed\ProductPageSearch\Dependency\Facade\ProductPageSearchToStoreFacadeInterface $storeFacade
102
     * @param \Spryker\Zed\ProductPageSearch\Business\Reader\AddToCartSkuReaderInterface $addToCartSkuReader
103
     */
104
    public function __construct(
105
        ProductPageSearchQueryContainerInterface $queryContainer,
106
        array $pageDataExpanderPlugins,
107
        array $productPageDataLoaderPlugins,
108
        array $productPageSearchCollectionFilterPlugins,
109
        ProductPageSearchMapperInterface $productPageSearchMapper,
110
        ProductPageSearchWriterInterface $productPageSearchWriter,
111
        ProductPageSearchConfig $productPageSearchConfig,
112
        ProductPageSearchToStoreFacadeInterface $storeFacade,
113
        AddToCartSkuReaderInterface $addToCartSkuReader
114
    ) {
115
        $this->queryContainer = $queryContainer;
116
        $this->pageDataExpanderPlugins = $pageDataExpanderPlugins;
117
        $this->productPageDataLoaderPlugins = $productPageDataLoaderPlugins;
118
        $this->productPageSearchCollectionFilterPlugins = $productPageSearchCollectionFilterPlugins;
119
        $this->productPageSearchMapper = $productPageSearchMapper;
120
        $this->productPageSearchWriter = $productPageSearchWriter;
121
        $this->productPageSearchConfig = $productPageSearchConfig;
122
        $this->storeFacade = $storeFacade;
123
        $this->addToCartSkuReader = $addToCartSkuReader;
124
    }
125
126
    /**
127
     * @param array<int> $productAbstractIds
128
     *
129
     * @return void
130
     */
131
    public function publish(array $productAbstractIds)
132
    {
133
        $productAbstractIdsChunks = array_chunk(
134
            $productAbstractIds,
135
            $this->productPageSearchConfig->getProductAbstractPagePublishChunkSize(),
136
        );
137
138
        foreach ($productAbstractIdsChunks as $productAbstractIdsChunk) {
139
            $this->publishEntities($productAbstractIdsChunk, [], false);
140
        }
141
    }
142
143
    /**
144
     * @param array<int> $productAbstractIds
145
     * @param array<string> $pageDataExpanderPluginNames
146
     *
147
     * @return void
148
     */
149
    public function refresh(array $productAbstractIds, array $pageDataExpanderPluginNames = [])
150
    {
151
        $isPoolingStateChanged = $this->disableInstancePooling();
152
153
        $productAbstractIdsChunks = array_chunk(
154
            array_unique($productAbstractIds),
155
            $this->productPageSearchConfig->getProductAbstractPagePublishChunkSize(),
156
        );
157
158
        foreach ($productAbstractIdsChunks as $productAbstractIdsChunk) {
159
            $this->publishEntities($productAbstractIdsChunk, $pageDataExpanderPluginNames, true);
160
        }
161
162
        if ($isPoolingStateChanged) {
163
            $this->enableInstancePooling();
164
        }
165
    }
166
167
    /**
168
     * @param array<int> $productAbstractIds
169
     *
170
     * @return void
171
     */
172
    public function unpublish(array $productAbstractIds)
173
    {
174
        $productAbstractPageSearchEntities = $this->findProductAbstractPageSearchEntities($productAbstractIds);
175
176
        $this->deleteProductAbstractPageSearchEntities($productAbstractPageSearchEntities);
177
    }
178
179
    /**
180
     * @param array<\Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch> $productAbstractPageSearchEntities
181
     *
182
     * @return void
183
     */
184
    protected function deleteProductAbstractPageSearchEntities(array $productAbstractPageSearchEntities)
185
    {
186
        foreach ($productAbstractPageSearchEntities as $productAbstractPageSearchEntity) {
187
            $productAbstractPageSearchEntity->delete();
188
        }
189
    }
190
191
    /**
192
     * @param array<int> $productAbstractIds
193
     * @param array<string> $pageDataExpanderPluginNames
194
     * @param bool $isRefresh
195
     *
196
     * @return void
197
     */
198
    protected function publishEntities(array $productAbstractIds, array $pageDataExpanderPluginNames, $isRefresh = false)
199
    {
200
        $pageDataExpanderPlugins = $this->getPageDataExpanderPlugins($pageDataExpanderPluginNames);
201
202
        $payloadTransfers = [];
203
        foreach ($productAbstractIds as $productAbstractId) {
204
            $payloadTransfers[$productAbstractId] = (new ProductPayloadTransfer())->setIdProductAbstract($productAbstractId);
205
        }
206
207
        $productPageLoadTransfer = (new ProductPageLoadTransfer())
208
            ->setProductAbstractIds($productAbstractIds)
209
            ->setPayloadTransfers($payloadTransfers);
210
211
        foreach ($this->productPageDataLoaderPlugins as $productPageDataLoaderPlugin) {
212
            $productPageLoadTransfer = $productPageDataLoaderPlugin->expandProductPageDataTransfer($productPageLoadTransfer);
213
        }
214
215
        $productAbstractLocalizedEntities = $this->findProductAbstractLocalizedEntities($productAbstractIds);
216
        $productCategories = $this->getProductCategoriesByProductAbstractIds($productAbstractIds);
217
        $productAbstractLocalizedEntities = $this->hydrateProductAbstractLocalizedEntitiesWithProductCategories($productCategories, $productAbstractLocalizedEntities);
218
219
        if ($this->productPageSearchConfig->isProductAbstractAddToCartEnabled()) {
220
            $productAbstractLocalizedEntities = $this->hydrateProductAbstractLocalizedEntitiesWithProductAbstractAddToCartSku(
221
                $productAbstractLocalizedEntities,
222
                $productAbstractIds,
223
            );
224
        }
225
226
        $productAbstractPageSearchEntities = $this->findProductAbstractPageSearchEntities($productAbstractIds);
227
        if (!$productAbstractLocalizedEntities) {
228
            $this->deleteProductAbstractPageSearchEntities($productAbstractPageSearchEntities);
229
230
            return;
231
        }
232
233
        $this->storeData(
234
            $productAbstractLocalizedEntities,
235
            $productAbstractPageSearchEntities,
236
            $pageDataExpanderPlugins,
237
            $productPageLoadTransfer,
238
            $isRefresh,
239
        );
240
    }
241
242
    /**
243
     * @param array<array<string, mixed>> $productAbstractLocalizedEntities
244
     * @param array<\Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch> $productAbstractPageSearchEntities
245
     * @param array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface> $pageDataExpanderPlugins
246
     * @param \Generated\Shared\Transfer\ProductPageLoadTransfer $productPageLoadTransfer
247
     * @param bool $isRefresh
248
     *
249
     * @return void
250
     */
251
    protected function storeData(
252
        array $productAbstractLocalizedEntities,
253
        array $productAbstractPageSearchEntities,
254
        array $pageDataExpanderPlugins,
255
        ProductPageLoadTransfer $productPageLoadTransfer,
256
        $isRefresh = false
257
    ) {
258
        $pairedEntities = $this->pairProductAbstractLocalizedEntitiesWithProductAbstractPageSearchEntities(
259
            $productAbstractLocalizedEntities,
260
            $productAbstractPageSearchEntities,
261
            $productPageLoadTransfer,
262
        );
263
264
        $productPageSearchTransfers = $this->mapPairedEntitiesToProductPageSearchTransfers(
265
            $pairedEntities,
266
            $isRefresh,
267
        );
268
        $productPageSearchTransfers = $this->executeProductPageSearchCollectionFilterPlugins($productPageSearchTransfers);
269
        $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract = $this->getProductPageSearchTransfersIndexedByLocaleAndIdProductAbstract(
270
            $productPageSearchTransfers,
271
        );
272
273
        foreach ($pairedEntities as $pairedEntity) {
274
            /** @var array|null $productAbstractLocalizedEntity */
275
            $productAbstractLocalizedEntity = $pairedEntity[static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY];
276
            /** @var \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity */
277
            $productAbstractPageSearchEntity = $pairedEntity[static::PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY];
278
            $store = $pairedEntity[static::STORE_NAME];
279
            $locale = $pairedEntity[static::LOCALE_NAME];
280
281
            if ($productAbstractLocalizedEntity === null || !$this->isActual($productAbstractLocalizedEntity)) {
282
                $this->deleteProductAbstractPageSearchEntity($productAbstractPageSearchEntity);
283
284
                continue;
285
            }
286
287
            $idProductAbstract = $productAbstractLocalizedEntity['fk_product_abstract'];
288
            $productPageSearchTransfer = $this->findProductPageSearchTransferFromIndexedList(
289
                $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract,
290
                $idProductAbstract,
291
                $locale,
292
                $store,
293
            );
294
295
            if ($productPageSearchTransfer === null) {
296
                $this->deleteProductAbstractPageSearchEntity($productAbstractPageSearchEntity);
297
298
                continue;
299
            }
300
301
            $this->storeProductAbstractPageSearchEntity(
302
                $productAbstractLocalizedEntity,
303
                $productAbstractPageSearchEntity,
304
                $productPageSearchTransfer,
305
                $store,
306
                $locale,
307
                $pageDataExpanderPlugins,
308
            );
309
        }
310
    }
311
312
    /**
313
     * @param \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity
314
     *
315
     * @return void
316
     */
317
    protected function deleteProductAbstractPageSearchEntity(SpyProductAbstractPageSearch $productAbstractPageSearchEntity)
318
    {
319
        if (!$productAbstractPageSearchEntity->isNew()) {
320
            $productAbstractPageSearchEntity->delete();
321
        }
322
    }
323
324
    /**
325
     * @param array $productAbstractLocalizedEntity
326
     * @param \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity
327
     * @param \Generated\Shared\Transfer\ProductPageSearchTransfer $productPageSearchTransfer
328
     * @param string $storeName
329
     * @param string $localeName
330
     * @param array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface> $pageDataExpanderPlugins
331
     *
332
     * @return void
333
     */
334
    protected function storeProductAbstractPageSearchEntity(
335
        array $productAbstractLocalizedEntity,
336
        SpyProductAbstractPageSearch $productAbstractPageSearchEntity,
337
        ProductPageSearchTransfer $productPageSearchTransfer,
338
        string $storeName,
339
        string $localeName,
340
        array $pageDataExpanderPlugins
341
    ) {
342
        $productPageSearchTransfer->setStore($storeName);
343
        $productPageSearchTransfer->setLocale($localeName);
344
345
        $this->expandPageSearchTransferWithPlugins($pageDataExpanderPlugins, $productAbstractLocalizedEntity, $productPageSearchTransfer);
346
347
        $searchDocument = $this->productPageSearchMapper->mapToSearchData($productPageSearchTransfer);
348
349
        $this->productPageSearchWriter->save($productPageSearchTransfer, $searchDocument, $productAbstractPageSearchEntity);
350
    }
351
352
    /**
353
     * @param array $productAbstractLocalizedEntity
354
     *
355
     * @return bool
356
     */
357
    protected function isActual(array $productAbstractLocalizedEntity): bool
358
    {
359
        foreach ($productAbstractLocalizedEntity['SpyProductAbstract']['SpyProducts'] as $spyProduct) {
360
            if ($spyProduct['is_active'] && $this->isSearchable($spyProduct, $productAbstractLocalizedEntity['fk_locale'])) {
361
                return true;
362
            }
363
        }
364
365
        return false;
366
    }
367
368
    /**
369
     * @param array $spyProduct
370
     * @param int $idLocale
371
     *
372
     * @return bool
373
     */
374
    protected function isSearchable(array $spyProduct, int $idLocale): bool
375
    {
376
        foreach ($spyProduct['SpyProductSearches'] as $spyProductSearch) {
377
            if ($spyProductSearch['fk_locale'] === $idLocale && $spyProductSearch['is_searchable'] === true) {
378
                return true;
379
            }
380
        }
381
382
        return false;
383
    }
384
385
    /**
386
     * Retrieves the ProductPageSearchTransfer from the storage entity (if it existed already) or populates it from the localized entity.
387
     *
388
     * @param array $productAbstractLocalizedEntity
389
     * @param \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity
390
     * @param bool $isRefresh
391
     *
392
     * @return \Generated\Shared\Transfer\ProductPageSearchTransfer
393
     */
394
    protected function getProductPageSearchTransfer(
395
        array $productAbstractLocalizedEntity,
396
        SpyProductAbstractPageSearch $productAbstractPageSearchEntity,
397
        $isRefresh = false
398
    ): ProductPageSearchTransfer {
399
        if ($isRefresh && !$productAbstractPageSearchEntity->isNew()) {
400
            return $this->refreshProductPageSearchTransfer($productAbstractPageSearchEntity);
401
        }
402
403
        return $this->productPageSearchMapper->mapToProductPageSearchTransfer($productAbstractLocalizedEntity);
404
    }
405
406
    /**
407
     * @param \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity
408
     *
409
     * @return \Generated\Shared\Transfer\ProductPageSearchTransfer
410
     */
411
    protected function refreshProductPageSearchTransfer(
412
        SpyProductAbstractPageSearch $productAbstractPageSearchEntity
413
    ): ProductPageSearchTransfer {
414
        return $this->productPageSearchMapper->mapToProductPageSearchTransferFromJson($productAbstractPageSearchEntity->getStructuredData());
415
    }
416
417
    /**
418
     * @param array<string> $pageDataExpanderPluginNames
419
     *
420
     * @return array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface>
421
     */
422
    protected function getPageDataExpanderPlugins(array $pageDataExpanderPluginNames)
423
    {
424
        if (!$pageDataExpanderPluginNames) {
425
            return $this->pageDataExpanderPlugins;
426
        }
427
428
        $selectedExpanderPlugins = [];
429
        foreach ($pageDataExpanderPluginNames as $pageDataExpanderPluginName) {
430
            $this->assertPageDataExpanderPluginName($pageDataExpanderPluginName);
431
432
            $selectedExpanderPlugins[] = $this->pageDataExpanderPlugins[$pageDataExpanderPluginName];
433
        }
434
435
        return $selectedExpanderPlugins;
436
    }
437
438
    /**
439
     * @param string $pageDataExpanderPluginName
440
     *
441
     * @throws \Spryker\Zed\ProductPageSearch\Business\Exception\PluginNotFoundException
442
     *
443
     * @return void
444
     */
445
    protected function assertPageDataExpanderPluginName($pageDataExpanderPluginName)
446
    {
447
        if (!isset($this->pageDataExpanderPlugins[$pageDataExpanderPluginName])) {
448
            throw new PluginNotFoundException(sprintf('The plugin with this name: %s is not found', $pageDataExpanderPluginName));
449
        }
450
    }
451
452
    /**
453
     * @param array<\Spryker\Zed\ProductPageSearch\Dependency\Plugin\ProductPageDataExpanderInterface> $pageDataExpanderPlugins
454
     * @param array<string, mixed> $productAbstractLocalizedEntity
455
     * @param \Generated\Shared\Transfer\ProductPageSearchTransfer $productPageSearchTransfer
456
     *
457
     * @return void
458
     */
459
    protected function expandPageSearchTransferWithPlugins(
460
        array $pageDataExpanderPlugins,
461
        array $productAbstractLocalizedEntity,
462
        ProductPageSearchTransfer $productPageSearchTransfer
463
    ) {
464
        foreach ($pageDataExpanderPlugins as $pageDataExpanderPlugin) {
465
            $pageDataExpanderPlugin->expandProductPageData($productAbstractLocalizedEntity, $productPageSearchTransfer);
466
        }
467
    }
468
469
    /**
470
     * - Returns a paired array with all provided entities.
471
     * - ProductAbstractLocalizedEntities without ProductAbstractPageSearchEntity are paired with a newly created ProductAbstractPageSearchEntity.
472
     * - ProductAbstractPageSearchEntity without ProductAbstractLocalizedEntities (left outs) are paired with NULL.
473
     * - ProductAbstractLocalizedEntities are paired multiple times per store.
474
     *
475
     * @param array<array<string, mixed>> $productAbstractLocalizedEntities
476
     * @param array<\Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch> $productAbstractPageSearchEntities
477
     * @param \Generated\Shared\Transfer\ProductPageLoadTransfer $productPageLoadTransfer
478
     *
479
     * @return array
480
     */
481
    protected function pairProductAbstractLocalizedEntitiesWithProductAbstractPageSearchEntities(
482
        array $productAbstractLocalizedEntities,
483
        array $productAbstractPageSearchEntities,
484
        ProductPageLoadTransfer $productPageLoadTransfer
485
    ) {
486
        $mappedProductAbstractPageSearchEntities = $this->mapProductAbstractPageSearchEntities($productAbstractPageSearchEntities);
487
488
        $pairs = [];
489
        $productPayloadTransfers = $productPageLoadTransfer->getPayloadTransfers();
490
        foreach ($productAbstractLocalizedEntities as $productAbstractLocalizedEntity) {
491
            [$pairs, $mappedProductAbstractPageSearchEntities] = $this->pairProductAbstractLocalizedEntityWithProductAbstractPageSearchEntityByStoresAndLocale(
492
                $productAbstractLocalizedEntity['fk_product_abstract'],
493
                $productAbstractLocalizedEntity['Locale']['locale_name'],
494
                $productPayloadTransfers[$productAbstractLocalizedEntity['fk_product_abstract']],
495
                $productAbstractLocalizedEntity['SpyProductAbstract']['SpyProductAbstractStores'],
496
                $productAbstractLocalizedEntity,
497
                $mappedProductAbstractPageSearchEntities,
498
                $pairs,
499
            );
500
        }
501
502
        $pairs = $this->pairRemainingProductAbstractPageSearchEntities($mappedProductAbstractPageSearchEntities, $pairs);
503
504
        return $pairs;
505
    }
506
507
    /**
508
     * @param array<int> $productAbstractIds
509
     *
510
     * @return array
511
     */
512
    protected function findProductAbstractLocalizedEntities(array $productAbstractIds)
513
    {
514
        $allProductAbstractLocalizedEntities = [];
515
        $localesByStore = [];
516
        foreach ($this->storeFacade->getAllStores() as $storeTransfer) {
517
            $productAbstractLocalizedEntities = $this
518
                ->queryContainer
519
                ->queryProductAbstractLocalizedEntitiesByProductAbstractIdsAndStore($productAbstractIds, $storeTransfer)
520
                ->find()
521
                ->getData();
522
523
            if (!isset($localesByStore[$storeTransfer->getName()])) {
524
                $localesByStore[$storeTransfer->getName()] = $storeTransfer->getAvailableLocaleIsoCodes();
525
            }
526
            $productConcreteEntities = $this->getProductConcreteEntitiesWithProductSearchEntities($productAbstractIds, $localesByStore[$storeTransfer->getName()]);
527
            $allProductAbstractLocalizedEntities[] = $this->hydrateProductAbstractLocalizedEntitiesWithProductConcreteEntities($productConcreteEntities, $productAbstractLocalizedEntities);
528
        }
529
530
        return array_merge(...$allProductAbstractLocalizedEntities);
531
    }
532
533
    /**
534
     * @param array<int> $productAbstractIds
535
     * @param array<string> $localeIsoCodes
536
     *
537
     * @return array
538
     */
539
    protected function getProductConcreteEntitiesWithProductSearchEntities(array $productAbstractIds, array $localeIsoCodes): array
540
    {
541
        $productConcreteEntities = $this->getProductConcreteEntitiesByProductAbstractIdsAndLocaleIsoCodes($productAbstractIds, $localeIsoCodes);
542
        $productSearchEntities = $this->getProductSearchEntitiesByProductConcreteIdsAndLocaleIsoCodes(array_column($productConcreteEntities, 'id_product'), $localeIsoCodes);
543
        $productConcreteEntities = $this->hydrateProductConcreteEntitiesWithProductSearchEntities($productSearchEntities, $productConcreteEntities);
544
545
        return $productConcreteEntities;
546
    }
547
548
    /**
549
     * @param array<int> $productAbstractIds
550
     * @param array<string> $localeIsoCodes
551
     *
552
     * @return array
553
     */
554
    protected function getProductConcreteEntitiesByProductAbstractIdsAndLocaleIsoCodes(array $productAbstractIds, array $localeIsoCodes): array
555
    {
556
        return $this->queryContainer
557
            ->queryProductConcretesByAbstractProductIdsAndLocaleIsoCodes($productAbstractIds, $localeIsoCodes)
558
            ->find()
559
            ->getData();
560
    }
561
562
    /**
563
     * @param array<int> $productConcreteIds
564
     * @param array<string> $localeIsoCodes
565
     *
566
     * @return array
567
     */
568
    protected function getProductSearchEntitiesByProductConcreteIdsAndLocaleIsoCodes(array $productConcreteIds, array $localeIsoCodes): array
569
    {
570
        return $this->queryContainer
571
            ->queryProductSearchByProductConcreteIdsAndLocaleIsoCodes($productConcreteIds, $localeIsoCodes)
572
            ->find()
573
            ->getData();
574
    }
575
576
    /**
577
     * @param array $productSearchEntities
578
     * @param array $productConcreteEntities
579
     *
580
     * @return array
581
     */
582
    protected function hydrateProductConcreteEntitiesWithProductSearchEntities(array $productSearchEntities, array $productConcreteEntities): array
583
    {
584
        $productSearchByProductConcreteId = [];
585
586
        foreach ($productSearchEntities as $productSearch) {
587
            $productSearchByProductConcreteId[$productSearch['fk_product']][] = $productSearch;
588
        }
589
590
        foreach ($productConcreteEntities as $key => $productConcreteEntity) {
591
            $productConcreteId = (int)$productConcreteEntity['id_product'];
592
            $productConcreteEntities[$key]['SpyProductSearches'] = $productSearchByProductConcreteId[$productConcreteId] ?? [];
593
        }
594
595
        return $productConcreteEntities;
596
    }
597
598
    /**
599
     * @param array $productCategories
600
     * @param array $productAbstractLocalizedEntities
601
     *
602
     * @return array
603
     */
604
    protected function hydrateProductAbstractLocalizedEntitiesWithProductCategories(array $productCategories, array $productAbstractLocalizedEntities)
605
    {
606
        $productCategoriesByProductAbstractId = [];
607
608
        foreach ($productCategories as $productCategory) {
609
            $productCategoriesByProductAbstractId[$productCategory['fk_product_abstract']][] = $productCategory;
610
        }
611
612
        foreach ($productAbstractLocalizedEntities as $key => $productAbstractLocalizedEntity) {
613
            $productAbstractId = (int)$productAbstractLocalizedEntity['fk_product_abstract'];
614
            $productAbstractLocalizedEntities[$key]['SpyProductAbstract']['SpyProductCategories']
615
                = $productCategoriesByProductAbstractId[$productAbstractId] ?? [];
616
        }
617
618
        return $productAbstractLocalizedEntities;
619
    }
620
621
    /**
622
     * @param array $productConcreteData
623
     * @param array $productAbstractLocalizedEntities
624
     *
625
     * @return array
626
     */
627
    protected function hydrateProductAbstractLocalizedEntitiesWithProductConcreteEntities(
628
        array $productConcreteData,
629
        array $productAbstractLocalizedEntities
630
    ): array {
631
        $productConcretesByProductAbstractId = [];
632
        foreach ($productConcreteData as $productConcrete) {
633
            $productConcretesByProductAbstractId[$productConcrete['fk_product_abstract']][] = $productConcrete;
634
        }
635
636
        foreach ($productAbstractLocalizedEntities as $key => $productAbstractLocalizedEntity) {
637
            $productAbstractId = (int)$productAbstractLocalizedEntity['fk_product_abstract'];
638
            $productAbstractLocalizedEntities[$key]['SpyProductAbstract']['SpyProducts'] = $productConcretesByProductAbstractId[$productAbstractId] ?? [];
639
        }
640
641
        return $productAbstractLocalizedEntities;
642
    }
643
644
    /**
645
     * @param array<int> $productAbstractIds
646
     *
647
     * @return array
648
     */
649
    protected function getProductCategoriesByProductAbstractIds(array $productAbstractIds)
650
    {
651
        return $this->queryContainer->queryAllProductCategories($productAbstractIds)->find()->getData();
652
    }
653
654
    /**
655
     * @param array<int> $productAbstractIds
656
     *
657
     * @return array<\Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch>
658
     */
659
    protected function findProductAbstractPageSearchEntities(array $productAbstractIds)
660
    {
661
        return $this->queryContainer->queryProductAbstractSearchPageByIds($productAbstractIds)->find()->getArrayCopy();
662
    }
663
664
    /**
665
     * @param array<\Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch> $productAbstractPageSearchEntities
666
     *
667
     * @return array
668
     */
669
    protected function mapProductAbstractPageSearchEntities(array $productAbstractPageSearchEntities)
670
    {
671
        $mappedProductAbstractPageSearchEntities = [];
672
        foreach ($productAbstractPageSearchEntities as $entity) {
673
            $mappedProductAbstractPageSearchEntities[$entity->getFkProductAbstract()][$entity->getStore()][$entity->getLocale()] = $entity;
674
        }
675
676
        return $mappedProductAbstractPageSearchEntities;
677
    }
678
679
    /**
680
     * @param array $mappedProductAbstractPageSearchEntities
681
     * @param array $pairs
682
     *
683
     * @return array
684
     */
685
    protected function pairRemainingProductAbstractPageSearchEntities(array $mappedProductAbstractPageSearchEntities, array $pairs)
686
    {
687
        array_walk_recursive($mappedProductAbstractPageSearchEntities, function (SpyProductAbstractPageSearch $productAbstractPageSearchEntity) use (&$pairs) {
688
            $pairs[] = [
689
                static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY => null,
690
                static::PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY => $productAbstractPageSearchEntity,
691
                static::LOCALE_NAME => $productAbstractPageSearchEntity->getLocale(),
692
                static::STORE_NAME => $productAbstractPageSearchEntity->getStore(),
693
            ];
694
        });
695
696
        return $pairs;
697
    }
698
699
    /**
700
     * @param int $idProductAbstract
701
     * @param string $localeName
702
     * @param \Generated\Shared\Transfer\ProductPayloadTransfer $productPayloadTransfer
703
     * @param array $productAbstractStores
704
     * @param array $productAbstractLocalizedEntity
705
     * @param array $mappedProductAbstractPageSearchEntities
706
     * @param array $pairs
707
     *
708
     * @return array
709
     */
710
    protected function pairProductAbstractLocalizedEntityWithProductAbstractPageSearchEntityByStoresAndLocale(
711
        $idProductAbstract,
712
        $localeName,
713
        ProductPayloadTransfer $productPayloadTransfer,
714
        array $productAbstractStores,
715
        array $productAbstractLocalizedEntity,
716
        array $mappedProductAbstractPageSearchEntities,
717
        array $pairs
718
    ) {
719
        foreach ($productAbstractStores as $productAbstractStore) {
720
            $storeName = $productAbstractStore['SpyStore']['name'];
721
            $productAbstractLocalizedEntity[SharedProductPageSearchConfig::PRODUCT_ABSTRACT_PAGE_LOAD_DATA] = $productPayloadTransfer;
722
723
            $searchEntity = $mappedProductAbstractPageSearchEntities[$idProductAbstract][$storeName][$localeName] ??
724
                new SpyProductAbstractPageSearch();
725
726
            unset($mappedProductAbstractPageSearchEntities[$idProductAbstract][$storeName][$localeName]);
727
728
            $pairs[] = [
729
                static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY => $productAbstractLocalizedEntity,
730
                static::PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY => $searchEntity,
731
                static::LOCALE_NAME => $localeName,
732
                static::STORE_NAME => $storeName,
733
            ];
734
        }
735
736
        return [$pairs, $mappedProductAbstractPageSearchEntities];
737
    }
738
739
    /**
740
     * @param array $productAbstractLocalizedEntities
741
     * @param array<int> $productAbstractIds
742
     *
743
     * @return array
744
     */
745
    protected function hydrateProductAbstractLocalizedEntitiesWithProductAbstractAddToCartSku(
746
        array $productAbstractLocalizedEntities,
747
        array $productAbstractIds
748
    ): array {
749
        $productAbstractStoreIds = [];
750
        foreach ($productAbstractLocalizedEntities as $productAbstractLocalizedEntity) {
751
            $productAbstractId = (int)$productAbstractLocalizedEntity['fk_product_abstract'];
752
            foreach ($productAbstractLocalizedEntity['SpyProductAbstract']['SpyProductAbstractStores'] as $productAbstractStoreData) {
753
                $storeId = (int)$productAbstractStoreData['SpyStore']['id_store'];
754
                $productAbstractStoreIds[$productAbstractId][] = $storeId;
755
            }
756
        }
757
758
        $productConcreteSkuMapByIdProductAbstract = $this->addToCartSkuReader->getProductAbstractAddToCartSkus($productAbstractIds, $productAbstractStoreIds);
759
760
        foreach ($productAbstractLocalizedEntities as &$productAbstractLocalizedEntity) {
761
            $productAbstractId = (int)$productAbstractLocalizedEntity['fk_product_abstract'];
762
            $productAbstractLocalizedEntity[ProductPageSearchTransfer::ADD_TO_CART_SKU] = $productConcreteSkuMapByIdProductAbstract[$productAbstractId] ?? null;
763
        }
764
765
        return $productAbstractLocalizedEntities;
766
    }
767
768
    /**
769
     * @param array $pairedEntities
770
     * @param bool $isRefresh
771
     *
772
     * @return array
773
     */
774
    protected function mapPairedEntitiesToProductPageSearchTransfers(
775
        array $pairedEntities,
776
        bool $isRefresh
777
    ): array {
778
        $productAbstractPageSearchTransfers = [];
779
780
        foreach ($pairedEntities as $pairedEntity) {
781
            /** @var array|null $productAbstractLocalizedEntity */
782
            $productAbstractLocalizedEntity = $pairedEntity[static::PRODUCT_ABSTRACT_LOCALIZED_ENTITY] ?? null;
783
            /** @var \Orm\Zed\ProductPageSearch\Persistence\SpyProductAbstractPageSearch $productAbstractPageSearchEntity */
784
            $productAbstractPageSearchEntity = $pairedEntity[static::PRODUCT_ABSTRACT_PAGE_SEARCH_ENTITY];
785
786
            if (!$productAbstractLocalizedEntity) {
787
                continue;
788
            }
789
790
            $productAbstractPageSearchTransfers[] = $this->getProductPageSearchTransfer(
791
                $productAbstractLocalizedEntity,
792
                $productAbstractPageSearchEntity,
793
                $isRefresh,
794
            );
795
        }
796
797
        return $productAbstractPageSearchTransfers;
798
    }
799
800
    /**
801
     * @param array<\Generated\Shared\Transfer\ProductPageSearchTransfer> $productPageSearchTransfers
802
     *
803
     * @return array<\Generated\Shared\Transfer\ProductPageSearchTransfer>
804
     */
805
    protected function executeProductPageSearchCollectionFilterPlugins(array $productPageSearchTransfers): array
806
    {
807
        foreach ($this->productPageSearchCollectionFilterPlugins as $productPageSearchCollectionFilterPlugin) {
808
            $productPageSearchTransfers = $productPageSearchCollectionFilterPlugin->filter($productPageSearchTransfers);
809
        }
810
811
        return $productPageSearchTransfers;
812
    }
813
814
    /**
815
     * @param array<\Generated\Shared\Transfer\ProductPageSearchTransfer> $productPageSearchTransfers
816
     *
817
     * @return array<string, array<int, list<\Generated\Shared\Transfer\ProductPageSearchTransfer>>>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, array<int,...ctPageSearchTransfer>>> at position 8 could not be parsed: Expected '>' at position 8, but found 'list'.
Loading history...
818
     */
819
    protected function getProductPageSearchTransfersIndexedByLocaleAndIdProductAbstract(array $productPageSearchTransfers): array
820
    {
821
        $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract = [];
822
        foreach ($productPageSearchTransfers as $productPageSearchTransfer) {
823
            $idProductAbstract = $productPageSearchTransfer->getIdProductAbstractOrFail();
824
            $locale = $productPageSearchTransfer->getLocaleOrFail();
825
            $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract[$locale][$idProductAbstract][] = $productPageSearchTransfer;
826
        }
827
828
        return $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract;
829
    }
830
831
    /**
832
     * @param array<string, array<int, list<\Generated\Shared\Transfer\ProductPageSearchTransfer>>> $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, array<int,...ctPageSearchTransfer>>> at position 8 could not be parsed: Expected '>' at position 8, but found 'list'.
Loading history...
833
     * @param int $idProductAbstract
834
     * @param string $locale
835
     * @param string $storeName
836
     *
837
     * @return \Generated\Shared\Transfer\ProductPageSearchTransfer|null
838
     */
839
    protected function findProductPageSearchTransferFromIndexedList(
840
        array $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract,
841
        int $idProductAbstract,
842
        string $locale,
843
        string $storeName
844
    ): ?ProductPageSearchTransfer {
845
        if (!isset($productPageSearchTransfersIndexedByLocaleAndIdProductAbstract[$locale][$idProductAbstract])) {
846
            return null;
847
        }
848
849
        $productPageSearchTransfers = $productPageSearchTransfersIndexedByLocaleAndIdProductAbstract[$locale][$idProductAbstract];
850
        foreach ($productPageSearchTransfers as $productPageSearchTransfer) {
851
            if ($productPageSearchTransfer->getStore() === $storeName) {
852
                return $productPageSearchTransfer;
853
            }
854
        }
855
856
        return $productPageSearchTransfers[0] ?? null;
857
    }
858
}
859