Issues (3641)

Collector/Business/Collector/AbstractCollector.php (2 issues)

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\Collector\Business\Collector;
9
10
use DateTime;
11
use Generated\Shared\Transfer\LocaleTransfer;
12
use Orm\Zed\Touch\Persistence\Map\SpyTouchTableMap;
13
use Orm\Zed\Touch\Persistence\SpyTouchQuery;
14
use PDO;
15
use Propel\Runtime\Formatter\StatementFormatter;
16
use Spryker\Shared\Gui\ProgressBar\ProgressBarBuilder;
17
use Spryker\Shared\KeyBuilder\KeyBuilderTrait;
18
use Spryker\Zed\Collector\Business\Exporter\Exception\DependencyException;
19
use Spryker\Zed\Collector\Business\Exporter\Writer\Storage\TouchUpdaterSet;
20
use Spryker\Zed\Collector\CollectorConfig;
21
use Spryker\Zed\Collector\Persistence\Collector\AbstractCollectorQuery;
22
use Spryker\Zed\Kernel\Locator;
23
use Spryker\Zed\Touch\Persistence\TouchQueryContainerInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
26
abstract class AbstractCollector
27
{
28
    use KeyBuilderTrait;
29
30
    /**
31
     * @var int
32
     */
33
    protected $chunkSize = 1000;
34
35
    /**
36
     * @var \Spryker\Zed\Touch\Persistence\TouchQueryContainerInterface
37
     */
38
    protected $touchQueryContainer;
39
40
    /**
41
     * @var \Spryker\Zed\Collector\Persistence\Collector\AbstractCollectorQuery
42
     */
43
    protected $queryBuilder;
44
45
    /**
46
     * @var \Generated\Shared\Transfer\LocaleTransfer
47
     */
48
    protected $locale;
49
50
    /**
51
     * @var \Generated\Shared\Transfer\StoreTransfer
52
     */
53
    protected $currentStoreBuffer;
54
55
    /**
56
     * @param string $touchKey
57
     * @param array $collectItemData
58
     *
59
     * @return array
60
     */
61
    abstract protected function collectItem($touchKey, array $collectItemData);
62
63
    /**
64
     * @return string
65
     */
66
    abstract protected function collectResourceType();
67
68
    /**
69
     * @return \Spryker\Service\UtilDataReader\Model\BatchIterator\CountableIteratorInterface
70
     */
71
    abstract protected function generateBatchIterator();
72
73
    /**
74
     * @param \Orm\Zed\Touch\Persistence\SpyTouchQuery $touchQuery
75
     * @param \Generated\Shared\Transfer\LocaleTransfer $localeTransfer
76
     *
77
     * @return void
78
     */
79
    abstract protected function prepareCollectorScope(SpyTouchQuery $touchQuery, LocaleTransfer $localeTransfer);
80
81
    /**
82
     * @param array $collectItemData
83
     *
84
     * @return bool True if the item can be exported; false if the item should be removed when stored.
85
     */
86
    protected function isStorable(array $collectItemData)
87
    {
88
        return true;
89
    }
90
91
    /**
92
     * @return \Generated\Shared\Transfer\StoreTransfer
93
     */
94
    protected function getCurrentStore()
95
    {
96
        if ($this->currentStoreBuffer === null) {
97
            // Deprecated: inject StoreFacade through constructor
98
            /** @var \Generated\Zed\Ide\AutoCompletion&\Spryker\Shared\Kernel\LocatorLocatorInterface $locator */
99
            $locator = Locator::getInstance();
100
            $this->currentStoreBuffer = $locator->store()->facade()->getCurrentStore();
101
        }
102
103
        return $this->currentStoreBuffer;
104
    }
105
106
    /**
107
     * @param \Spryker\Zed\Touch\Persistence\TouchQueryContainerInterface $touchQueryContainer
108
     *
109
     * @return void
110
     */
111
    public function setTouchQueryContainer(TouchQueryContainerInterface $touchQueryContainer)
112
    {
113
        $this->touchQueryContainer = $touchQueryContainer;
114
    }
115
116
    /**
117
     * @param \Spryker\Zed\Collector\Persistence\Collector\AbstractCollectorQuery $queryBuilder
118
     *
119
     * @return void
120
     */
121
    public function setQueryBuilder(AbstractCollectorQuery $queryBuilder)
122
    {
123
        $this->queryBuilder = $queryBuilder;
124
    }
125
126
    /**
127
     * @return int
128
     */
129
    public function getChunkSize()
130
    {
131
        return $this->chunkSize;
132
    }
133
134
    /**
135
     * @param int $chunkSize
136
     *
137
     * @return void
138
     */
139
    public function setChunkSize($chunkSize)
140
    {
141
        $this->chunkSize = $chunkSize;
142
    }
143
144
    /**
145
     * @param array $collectedSet
146
     * @param \Generated\Shared\Transfer\LocaleTransfer $localeTransfer
147
     * @param \Spryker\Zed\Collector\Business\Exporter\Writer\Storage\TouchUpdaterSet $touchUpdaterSet
148
     *
149
     * @return array
150
     */
151
    protected function collectData(array $collectedSet, LocaleTransfer $localeTransfer, TouchUpdaterSet $touchUpdaterSet)
152
    {
153
        $setToExport = [];
154
155
        foreach ($collectedSet as $index => $collectedItemData) {
156
            if (!$this->isStorable($collectedItemData)) {
157
                continue;
158
            }
159
160
            $touchKey = $this->collectKey(
161
                $collectedItemData[CollectorConfig::COLLECTOR_RESOURCE_ID],
162
                $localeTransfer->getLocaleName(),
163
                $collectedItemData,
164
            );
165
            $setToExport[$touchKey] = $this->processCollectedItem($touchKey, $collectedItemData, $touchUpdaterSet);
166
        }
167
168
        return $setToExport;
169
    }
170
171
    /**
172
     * @param array $collectedSet
173
     * @param \Generated\Shared\Transfer\LocaleTransfer $localeTransfer
174
     *
175
     * @return array<string>
176
     */
177
    protected function collectExpiredData(array $collectedSet, LocaleTransfer $localeTransfer)
178
    {
179
        $expiredData = [];
180
181
        foreach ($collectedSet as $index => $collectedItemData) {
182
            if ($this->isStorable($collectedItemData)) {
183
                continue;
184
            }
185
186
            $touchKey = $this->collectKey(
187
                $collectedItemData[CollectorConfig::COLLECTOR_RESOURCE_ID],
188
                $localeTransfer->getLocaleName(),
189
                $collectedItemData,
190
            );
191
            $expiredData[$touchKey] = $collectedItemData;
192
        }
193
194
        return $expiredData;
195
    }
196
197
    /**
198
     * @param mixed $data
199
     * @param string $localeName
200
     * @param array $collectedItemData
201
     *
202
     * @return string
203
     */
204
    protected function collectKey($data, $localeName, array $collectedItemData)
205
    {
206
        return $this->generateKey($data, $localeName);
207
    }
208
209
    /**
210
     * @param string $touchKey
211
     * @param array $collectItemData
212
     * @param \Spryker\Zed\Collector\Business\Exporter\Writer\Storage\TouchUpdaterSet $touchUpdaterSet
213
     *
214
     * @return array
215
     */
216
    protected function processCollectedItem($touchKey, array $collectItemData, TouchUpdaterSet $touchUpdaterSet)
217
    {
218
        $this->appendTouchUpdaterSetItem(
219
            $touchUpdaterSet,
220
            $touchKey,
221
            $collectItemData[CollectorConfig::COLLECTOR_TOUCH_ID],
222
            $collectItemData,
223
        );
224
225
        return $this->collectItem($touchKey, $collectItemData);
226
    }
227
228
    /**
229
     * @param array $collectItemData
230
     *
231
     * @return int|null
232
     */
233
    protected function getCollectorStorageKeyId(array $collectItemData)
234
    {
235
        if (!isset($collectItemData[CollectorConfig::COLLECTOR_STORAGE_KEY])) {
236
            return null;
237
        }
238
239
        return $collectItemData[CollectorConfig::COLLECTOR_STORAGE_KEY];
240
    }
241
242
    /**
243
     * @param array $collectItemData
244
     *
245
     * @return int|null
246
     */
247
    protected function getCollectorSearchKeyId(array $collectItemData)
248
    {
249
        if (!isset($collectItemData[CollectorConfig::COLLECTOR_SEARCH_KEY])) {
250
            return null;
251
        }
252
253
        return $collectItemData[CollectorConfig::COLLECTOR_SEARCH_KEY];
254
    }
255
256
    /**
257
     * @param string $itemType
258
     * @param int $offset
259
     *
260
     * @return array<\Orm\Zed\Touch\Persistence\SpyTouch>
261
     */
262
    protected function getTouchCollectionToDelete($itemType, $offset = 0)
263
    {
264
        $deleteQuery = $this->touchQueryContainer->queryTouchDeleteStorageAndSearch($itemType, $this->getCurrentStore()->getIdStore(), $this->locale->getIdLocale());
265
        $deleteQuery
266
            ->withColumn(SpyTouchTableMap::COL_ID_TOUCH, CollectorConfig::COLLECTOR_TOUCH_ID)
267
            ->withColumn('search.key', CollectorConfig::COLLECTOR_SEARCH_KEY)
268
            ->withColumn('storage.key', CollectorConfig::COLLECTOR_STORAGE_KEY)
269
            ->setOffset($offset)
270
            ->setLimit($this->chunkSize)
271
            ->setFormatter(StatementFormatter::class);
272
273
        $params = [];
274
        $sql = $deleteQuery->createSelectSql($params);
275
        $params = $this->getTouchQueryParameters($deleteQuery);
276
        /** @var \Propel\Runtime\Connection\StatementInterface $statement */
277
        $statement = $this->touchQueryContainer->getConnection()->prepare($sql);
278
279
        $sqlParams = [];
280
        $step = 1;
281
        foreach ($params as $key => $value) {
282
            $sqlParams['p' . $step] = $value;
283
            $statement->bindParam(':p' . $step, $value);
284
            $step++;
285
        }
286
287
        $statement->execute($sqlParams);
288
289
        /** @phpstan-var array<\Orm\Zed\Touch\Persistence\SpyTouch> */
290
        return $statement->fetchAll(PDO::FETCH_ASSOC);
291
    }
292
293
    /**
294
     * @param array $entityCollection
295
     * @param string $touchKeyColumnName
296
     * @param \Spryker\Zed\Collector\Business\Exporter\Writer\Storage\TouchUpdaterSet $touchUpdaterSet
297
     *
298
     * @return array
299
     */
300
    protected function getKeysToDeleteAndUpdateTouchUpdaterSet(
301
        array $entityCollection,
302
        $touchKeyColumnName,
303
        TouchUpdaterSet $touchUpdaterSet
304
    ) {
305
        $keysToDelete = [];
306
307
        foreach ($entityCollection as $entityData) {
308
            $key = $entityData[$touchKeyColumnName];
309
310
            if (trim($key) !== '') {
311
                $keysToDelete[$key] = true;
312
                $this->appendTouchUpdaterSetItem(
313
                    $touchUpdaterSet,
314
                    $key,
315
                    $entityData[CollectorConfig::COLLECTOR_TOUCH_ID],
316
                    $entityData,
317
                );
318
            }
319
        }
320
321
        return $keysToDelete;
322
    }
323
324
    /**
325
     * @throws \Spryker\Zed\Collector\Business\Exporter\Exception\DependencyException
326
     *
327
     * @return void
328
     */
329
    protected function validateDependencies()
330
    {
331
        if (!($this->touchQueryContainer instanceof TouchQueryContainerInterface)) {
0 ignored issues
show
$this->touchQueryContainer is always a sub-type of Spryker\Zed\Touch\Persis...QueryContainerInterface.
Loading history...
332
            throw new DependencyException(sprintf(
333
                'touchQueryContainer does not implement TouchQueryContainerInterface in %s',
334
                static::class,
335
            ));
336
        }
337
338
        if (!($this->queryBuilder instanceof AbstractCollectorQuery)) {
0 ignored issues
show
$this->queryBuilder is always a sub-type of Spryker\Zed\Collector\Pe...\AbstractCollectorQuery.
Loading history...
339
            throw new DependencyException(sprintf(
340
                'queryBuilder does not implement AbstractCollectorQuery in %s',
341
                static::class,
342
            ));
343
        }
344
    }
345
346
    /**
347
     * @param \Orm\Zed\Touch\Persistence\SpyTouchQuery $baseQuery
348
     *
349
     * @return array
350
     */
351
    protected function getTouchQueryParameters(SpyTouchQuery $baseQuery)
352
    {
353
        $result = [];
354
        $baseParameters = $baseQuery->getParams();
355
356
        foreach ($baseParameters as $parameter) {
357
            $key = sprintf('%s.%s', $parameter['table'], $parameter['column']);
358
            $value = $parameter['value'];
359
            if ($value instanceof DateTime) {
360
                $value = $value->format(DateTime::ATOM);
361
            }
362
            $result[$key] = $value;
363
        }
364
365
        return $result;
366
    }
367
368
    /**
369
     * @param string $data Identifier.
370
     *
371
     * @return string
372
     */
373
    protected function buildKey($data)
374
    {
375
        return $this->collectResourceType() . '.' . $data;
376
    }
377
378
    /**
379
     * @return string
380
     */
381
    public function getBundleName()
382
    {
383
        return 'resource';
384
    }
385
386
    /**
387
     * @param \Spryker\Zed\Collector\Business\Exporter\Writer\Storage\TouchUpdaterSet $touchUpdaterSet
388
     * @param string $collectorKey
389
     * @param int $touchId
390
     * @param array<string, mixed> $data
391
     *
392
     * @return void
393
     */
394
    protected function appendTouchUpdaterSetItem(TouchUpdaterSet $touchUpdaterSet, $collectorKey, $touchId, array $data)
395
    {
396
        $touchUpdaterSet->add($collectorKey, $touchId, [
397
            CollectorConfig::COLLECTOR_STORAGE_KEY => $this->getCollectorStorageKeyId($data),
398
            CollectorConfig::COLLECTOR_SEARCH_KEY => $this->getCollectorSearchKeyId($data),
399
        ]);
400
    }
401
402
    /**
403
     * @param \Symfony\Component\Console\Output\OutputInterface $output
404
     * @param int $count
405
     *
406
     * @return \Symfony\Component\Console\Helper\ProgressBar
407
     */
408
    protected function generateProgressBar(OutputInterface $output, $count)
409
    {
410
        $builder = new ProgressBarBuilder($output, $count, $this->collectResourceType());
411
412
        return $builder->build();
413
    }
414
415
    /**
416
     * Display progress while counting data for real progress bar
417
     *
418
     * @param \Symfony\Component\Console\Output\OutputInterface $output
419
     *
420
     * @return void
421
     */
422
    protected function displayProgressWhileCountingBatchCollectionSize(OutputInterface $output)
423
    {
424
        $builder = new ProgressBarBuilder($output, 1, $this->collectResourceType());
425
        $progressBar = $builder->build();
426
427
        $progressBar->setFormat(" * %barTitle%\x0D ");
428
        $progressBar->start();
429
        $progressBar->advance();
430
        $progressBar->finish();
431
    }
432
}
433