Passed
Push — release-11.5.x ( e36eae...fbafb7 )
by Markus
34:11 queued 12:02
created

Queue   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 642
Duplicated Lines 0 %

Test Coverage

Coverage 94.63%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 53
eloc 125
c 2
b 0
f 0
dl 0
loc 642
ccs 141
cts 149
cp 0.9463
rs 6.96

32 Methods

Rating   Name   Duplication   Size   Complexity  
A getLastIndexTime() 0 11 2
A __construct() 0 15 1
A getInitializationService() 0 3 1
A getLastIndexedItemId() 0 10 2
A updateItem() 0 4 1
A getStatisticsBySite() 0 6 1
A markItemAsFailed() 0 3 1
A addNewItem() 0 21 5
A deleteItemsByType() 0 3 1
A getHookImplementation() 0 3 1
A deleteAllItems() 0 3 1
A deleteItem() 0 3 1
A containsIndexedItem() 0 3 1
A updateIndexTimeByItem() 0 3 1
B updateOrAddItemForAllRelatedRootPages() 0 43 8
A getErrorsBySite() 0 3 1
A resetAllErrors() 0 3 1
A containsItemWithRootPageId() 0 3 1
A getRecordCached() 0 12 2
A deleteItemsBySite() 0 3 1
A postProcessIndexQueueUpdateItem() 0 16 3
A getPageItemChangedTime() 0 7 2
A getItem() 0 3 1
A getAllItems() 0 3 1
A getItems() 0 3 1
A getItemChangedTime() 0 41 5
A getAllItemsCount() 0 3 1
A resetErrorsBySite() 0 3 1
A getItemsToIndex() 0 3 1
A resetErrorByItem() 0 3 1
A containsItem() 0 3 1
A setForcedChangeTimeByItem() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Queue 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 Queue, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace ApacheSolrForTypo3\Solr\IndexQueue;
19
20
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\QueueInitializationService;
21
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\QueueItemRepository;
22
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\ConfigurationAwareRecordService;
23
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\RootPageResolver;
24
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\Statistic\QueueStatistic;
25
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\Statistic\QueueStatisticsRepository;
26
use ApacheSolrForTypo3\Solr\Domain\Site\Site;
27
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
28
use ApacheSolrForTypo3\Solr\FrontendEnvironment;
29
use ApacheSolrForTypo3\Solr\System\Cache\TwoLevelCache;
30
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
31
use Doctrine\DBAL\ConnectionException;
32
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
33
use Doctrine\DBAL\Exception as DBALException;
34
use InvalidArgumentException;
35
use Throwable;
36
use TYPO3\CMS\Backend\Utility\BackendUtility;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
39
/**
40
 * The Indexing Queue. It allows us to decouple from frontend indexing and
41
 * reacting to the changes faster.
42
 *
43
 * @author Ingo Renner <[email protected]>
44
 */
45
class Queue
46
{
47
    /**
48
     * @var RootPageResolver
49
     */
50
    protected RootPageResolver $rootPageResolver;
51
52
    /**
53
     * @var ConfigurationAwareRecordService
54
     */
55
    protected ConfigurationAwareRecordService $recordService;
56
57
    /**
58
     * @var SolrLogManager
59
     */
60
    protected SolrLogManager $logger;
61
62
    /**
63
     * @var QueueItemRepository
64
     */
65
    protected QueueItemRepository $queueItemRepository;
66
67
    /**
68
     * @var QueueStatisticsRepository
69
     */
70
    protected QueueStatisticsRepository $queueStatisticsRepository;
71
72
    /**
73
     * @var QueueInitializationService
74
     */
75
    protected QueueInitializationService $queueInitializationService;
76
77
    /**
78
     * @var FrontendEnvironment
79
     */
80
    protected FrontendEnvironment $frontendEnvironment;
81
82
    /**
83
     * Queue constructor.
84
     * @param RootPageResolver|null $rootPageResolver
85
     * @param ConfigurationAwareRecordService|null $recordService
86
     * @param QueueItemRepository|null $queueItemRepository
87
     * @param QueueStatisticsRepository|null $queueStatisticsRepository
88
     * @param QueueInitializationService|null $queueInitializationService
89
     */
90 156
    public function __construct(
91
        RootPageResolver $rootPageResolver = null,
92
        ConfigurationAwareRecordService $recordService = null,
93
        QueueItemRepository $queueItemRepository = null,
94
        QueueStatisticsRepository $queueStatisticsRepository = null,
95
        QueueInitializationService $queueInitializationService = null,
96
        FrontendEnvironment $frontendEnvironment = null
97
    ) {
98 156
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
99 156
        $this->rootPageResolver = $rootPageResolver ?? GeneralUtility::makeInstance(RootPageResolver::class);
100 156
        $this->recordService = $recordService ?? GeneralUtility::makeInstance(ConfigurationAwareRecordService::class);
101 156
        $this->queueItemRepository = $queueItemRepository ?? GeneralUtility::makeInstance(QueueItemRepository::class);
102 156
        $this->queueStatisticsRepository = $queueStatisticsRepository ??  GeneralUtility::makeInstance(QueueStatisticsRepository::class);
103 156
        $this->queueInitializationService = $queueInitializationService ?? GeneralUtility::makeInstance(QueueInitializationService::class, /** @scrutinizer ignore-type */ $this);
104 156
        $this->frontendEnvironment = $frontendEnvironment ?? GeneralUtility::makeInstance(FrontendEnvironment::class);
105
    }
106
107
    // FIXME some of the methods should be renamed to plural forms
108
    // FIXME singular form methods should deal with exactly one item only
109
110
    /**
111
     * Returns the timestamp of the last indexing run.
112
     *
113
     * @param int $rootPageId The root page uid for which to get
114
     *      the last indexed item id
115
     * @return int Timestamp of last index run.
116
     * @throws DBALDriverException
117
     * @throws DBALException|\Doctrine\DBAL\DBALException
118
     */
119 2
    public function getLastIndexTime(int $rootPageId): int
120
    {
121 2
        $lastIndexTime = 0;
122
123 2
        $lastIndexedRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
124
125 2
        if ($lastIndexedRow[0]['indexed']) {
126 1
            $lastIndexTime = $lastIndexedRow[0]['indexed'];
127
        }
128
129 2
        return $lastIndexTime;
130
    }
131
132
    /**
133
     * Returns the uid of the last indexed item in the queue
134
     *
135
     * @param int $rootPageId The root page uid for which to get
136
     *      the last indexed item id
137
     * @return int The last indexed item's ID.
138
     * @throws DBALDriverException
139
     * @throws DBALException|\Doctrine\DBAL\DBALException
140
     */
141 3
    public function getLastIndexedItemId(int $rootPageId): int
142
    {
143 3
        $lastIndexedItemId = 0;
144
145 3
        $lastIndexedItemRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
146 3
        if ($lastIndexedItemRow[0]['uid']) {
147 2
            $lastIndexedItemId = $lastIndexedItemRow[0]['uid'];
148
        }
149
150 3
        return $lastIndexedItemId;
151
    }
152
153
    /**
154
     * @return QueueInitializationService
155
     */
156 6
    public function getInitializationService(): QueueInitializationService
157
    {
158 6
        return $this->queueInitializationService;
159
    }
160
161
    /**
162
     * Marks an item as needing (re)indexing.
163
     *
164
     * Like with Solr itself, there's no add method, just a simple update method
165
     * that handles the adds, too.
166
     *
167
     * The method creates or updates the index queue items for all related rootPageIds.
168
     *
169
     * @param string $itemType The item's type, usually a table name.
170
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
171
     * @param int $forcedChangeTime The change time for the item if set, otherwise value from getItemChangedTime() is used.
172
     * @return int Number of updated/created items
173
     * @throws DBALDriverException
174
     * @throws DBALException|\Doctrine\DBAL\DBALException
175
     * @throws Throwable
176
     */
177 94
    public function updateItem(string $itemType, $itemUid, int $forcedChangeTime = 0): int
178
    {
179 94
        $updateCount = $this->updateOrAddItemForAllRelatedRootPages($itemType, $itemUid, $forcedChangeTime);
180 94
        return $this->postProcessIndexQueueUpdateItem($itemType, $itemUid, $updateCount, $forcedChangeTime);
181
    }
182
183
    /**
184
     * Updates or adds the item for all relevant root pages.
185
     *
186
     * @param string $itemType The item's type, usually a table name.
187
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
188
     * @param int $forcedChangeTime The change time for the item if set, otherwise value from getItemChangedTime() is used.
189
     * @return int
190
     * @throws DBALDriverException
191
     * @throws DBALException|\Doctrine\DBAL\DBALException
192
     * @throws Throwable
193
     */
194 92
    protected function updateOrAddItemForAllRelatedRootPages(string $itemType, $itemUid, int $forcedChangeTime): int
195
    {
196 92
        $updateCount = 0;
197
        try {
198 92
            $rootPageIds = $this->rootPageResolver->getResponsibleRootPageIds($itemType, $itemUid);
0 ignored issues
show
Bug introduced by
It seems like $itemUid can also be of type string; however, parameter $uid of ApacheSolrForTypo3\Solr\...esponsibleRootPageIds() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

198
            $rootPageIds = $this->rootPageResolver->getResponsibleRootPageIds($itemType, /** @scrutinizer ignore-type */ $itemUid);
Loading history...
199 4
        } catch (InvalidArgumentException $e) {
200 4
            $this->deleteItem($itemType, $itemUid);
201 4
            return 0;
202
        }
203
204
        /* @var SiteRepository $siteRepository */
205 88
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
206 88
        foreach ($rootPageIds as $rootPageId) {
207 88
            $skipInvalidRootPage = $rootPageId === 0;
208 88
            if ($skipInvalidRootPage) {
209
                continue;
210
            }
211
212 88
            $site = $siteRepository->getSiteByRootPageId($rootPageId);
213 88
            if ($site === null) {
214
                continue;
215
            }
216
217 88
            $solrConfiguration = $site->getSolrConfiguration();
218 88
            $indexingConfiguration = $this->recordService->getIndexingConfigurationName($itemType, $itemUid, $solrConfiguration);
0 ignored issues
show
Bug introduced by
It seems like $itemUid can also be of type string; however, parameter $recordUid of ApacheSolrForTypo3\Solr\...xingConfigurationName() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

218
            $indexingConfiguration = $this->recordService->getIndexingConfigurationName($itemType, /** @scrutinizer ignore-type */ $itemUid, $solrConfiguration);
Loading history...
219 88
            if ($indexingConfiguration === null) {
220 3
                continue;
221
            }
222 87
            $indexingPriority = $solrConfiguration->getIndexQueueIndexingPriorityByConfigurationName($indexingConfiguration);
223 87
            $itemInQueueForRootPage = $this->containsItemWithRootPageId($itemType, $itemUid, $rootPageId);
224 87
            if ($itemInQueueForRootPage) {
225
                // update changed time if that item is in the queue already
226 19
                $changedTime = ($forcedChangeTime > 0) ? $forcedChangeTime : $this->getItemChangedTime($itemType, $itemUid);
227 19
                $updatedRows = $this->queueItemRepository->updateExistingItemByItemTypeAndItemUidAndRootPageId($itemType, $itemUid, $rootPageId, $changedTime, $indexingConfiguration, $indexingPriority);
0 ignored issues
show
Bug introduced by
It seems like $itemUid can also be of type string; however, parameter $itemUid of ApacheSolrForTypo3\Solr\...dItemUidAndRootPageId() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

227
                $updatedRows = $this->queueItemRepository->updateExistingItemByItemTypeAndItemUidAndRootPageId($itemType, /** @scrutinizer ignore-type */ $itemUid, $rootPageId, $changedTime, $indexingConfiguration, $indexingPriority);
Loading history...
228
            } else {
229
                // add the item since it's not in the queue yet
230 80
                $updatedRows = $this->addNewItem($itemType, $itemUid, $indexingConfiguration, $rootPageId, $indexingPriority);
231
            }
232
233 87
            $updateCount += $updatedRows;
234
        }
235
236 88
        return $updateCount;
237
    }
238
239
    /**
240
     * Executes the updateItem post-processing hook.
241
     *
242
     * @param string $itemType
243
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
244
     * @param int $updateCount
245
     * @param int $forcedChangeTime
246
     * @return int
247
     */
248 94
    protected function postProcessIndexQueueUpdateItem(
249
        string $itemType,
250
        $itemUid,
251
        int $updateCount,
252
        int $forcedChangeTime = 0
253
    ): int {
254 94
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['postProcessIndexQueueUpdateItem'] ?? null)) {
255 93
            return $updateCount;
256
        }
257
258 1
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['postProcessIndexQueueUpdateItem'] as $classReference) {
259 1
            $updateHandler = $this->getHookImplementation($classReference);
260 1
            $updateCount = $updateHandler->postProcessIndexQueueUpdateItem($itemType, $itemUid, $updateCount, $forcedChangeTime);
261
        }
262
263 1
        return $updateCount;
264
    }
265
266
    /**
267
     * @param string $classReference
268
     * @return object
269
     */
270
    protected function getHookImplementation(string $classReference): object
271
    {
272
        return GeneralUtility::makeInstance($classReference);
273
    }
274
275
    /**
276
     * Finds indexing errors for the current site
277
     *
278
     * @param Site $site
279
     * @return array Error items for the current site's Index Queue
280
     * @throws DBALDriverException
281
     * @throws DBALException|\Doctrine\DBAL\DBALException
282
     */
283 3
    public function getErrorsBySite(Site $site): array
284
    {
285 3
        return $this->queueItemRepository->findErrorsBySite($site);
286
    }
287
288
    /**
289
     * Resets all the errors for all index queue items.
290
     *
291
     * @return mixed
292
     * @throws DBALException|\Doctrine\DBAL\DBALException
293
     */
294 1
    public function resetAllErrors()
295
    {
296 1
        return $this->queueItemRepository->flushAllErrors();
297
    }
298
299
    /**
300
     * Resets the errors in the index queue for a specific site
301
     *
302
     * @param Site $site
303
     * @return mixed
304
     * @throws DBALException|\Doctrine\DBAL\DBALException
305
     */
306 1
    public function resetErrorsBySite(Site $site)
307
    {
308 1
        return $this->queueItemRepository->flushErrorsBySite($site);
309
    }
310
311
    /**
312
     * Resets the error in the index queue for a specific item
313
     *
314
     * @param Item $item
315
     * @return mixed
316
     * @throws DBALException|\Doctrine\DBAL\DBALException
317
     */
318 1
    public function resetErrorByItem(Item $item)
319
    {
320 1
        return $this->queueItemRepository->flushErrorByItem($item);
321
    }
322
323
    /**
324
     * Adds an item to the index queue.
325
     *
326
     * Not meant for public use.
327
     *
328
     * @param string $itemType The item's type, usually a table name.
329
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
330
     *      different value for non-database-record types.
331
     * @param string $indexingConfiguration The item's indexing configuration to use.
332
     *      Optional, overwrites existing / determined configuration.
333
     * @param int $rootPageId
334
     * @param int $indexingPriority
335
     * @return int
336
     * @throws DBALDriverException
337
     * @throws DBALException|\Doctrine\DBAL\DBALException
338
     */
339 80
    private function addNewItem(
340
        string $itemType,
341
        $itemUid,
342
        string $indexingConfiguration,
343
        int $rootPageId,
344
        int $indexingPriority = 0
345
    ): int {
346 80
        $additionalRecordFields = '';
347 80
        if ($itemType === 'pages') {
348 52
            $additionalRecordFields = ', doktype, uid';
349
        }
350
351 80
        $record = $this->getRecordCached($itemType, $itemUid, $additionalRecordFields);
352
353 80
        if (empty($record) || ($itemType === 'pages' && !$this->frontendEnvironment->isAllowedPageType($record, $indexingConfiguration))) {
354
            return 0;
355
        }
356
357 80
        $changedTime = $this->getItemChangedTime($itemType, $itemUid);
358
359 80
        return $this->queueItemRepository->add($itemType, $itemUid, $rootPageId, $changedTime, $indexingConfiguration, $indexingPriority);
0 ignored issues
show
Bug introduced by
It seems like $itemUid can also be of type string; however, parameter $itemUid of ApacheSolrForTypo3\Solr\...ueItemRepository::add() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

359
        return $this->queueItemRepository->add($itemType, /** @scrutinizer ignore-type */ $itemUid, $rootPageId, $changedTime, $indexingConfiguration, $indexingPriority);
Loading history...
360
    }
361
362
    /**
363
     * Get record to be added in addNewItem
364
     *
365
     * @param string $itemType The item's type, usually a table name.
366
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
367
     *      different value for non-database-record types.
368
     * @param string $additionalRecordFields for sql-query
369
     *
370
     * @return array|null
371
     */
372 80
    protected function getRecordCached(string $itemType, $itemUid, string $additionalRecordFields): ?array
373
    {
374 80
        $cache = GeneralUtility::makeInstance(TwoLevelCache::class, /** @scrutinizer ignore-type */ 'runtime');
375 80
        $cacheId = md5('Queue' . ':' . 'getRecordCached' . ':' . $itemType . ':' . $itemUid . ':' . 'pid' . $additionalRecordFields);
376
377 80
        $record = $cache->get($cacheId);
378 80
        if (empty($record)) {
379 80
            $record = BackendUtility::getRecord($itemType, $itemUid, 'pid' . $additionalRecordFields);
380 80
            $cache->set($cacheId, $record);
381
        }
382
383 80
        return $record;
384
    }
385
386
    /**
387
     * Determines the time for when an item should be indexed. This timestamp
388
     * is then stored in the changed column in the Index Queue.
389
     *
390
     * The changed timestamp usually is now - time(). For records which are set
391
     * to published at a later time, this timestamp is the start time. So if a
392
     * future start time has been set, that will be used to delay indexing
393
     * of an item.
394
     *
395
     * @param string $itemType The item's table name.
396
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
397
     *      different value for non-database-record types.
398
     * @return int Timestamp of the item's changed time or future start time
399
     * @throws DBALDriverException
400
     * @throws DBALException|\Doctrine\DBAL\DBALException
401
     */
402 87
    protected function getItemChangedTime(string $itemType, $itemUid): int
403
    {
404 87
        $itemTypeHasStartTimeColumn = false;
405 87
        $changedTimeColumns = $GLOBALS['TCA'][$itemType]['ctrl']['tstamp'];
406 87
        $startTime = 0;
407 87
        $pageChangedTime = 0;
408
409 87
        if (!empty($GLOBALS['TCA'][$itemType]['ctrl']['enablecolumns']['starttime'])) {
410 87
            $itemTypeHasStartTimeColumn = true;
411 87
            $changedTimeColumns .= ', ' . $GLOBALS['TCA'][$itemType]['ctrl']['enablecolumns']['starttime'];
412
        }
413 87
        if ($itemType === 'pages') {
414
            // does not carry time information directly, but needed to support
415
            // canonical pages
416 59
            $changedTimeColumns .= ', content_from_pid';
417
        }
418
419 87
        $record = BackendUtility::getRecord($itemType, $itemUid, $changedTimeColumns);
420 87
        $itemChangedTime = $record[$GLOBALS['TCA'][$itemType]['ctrl']['tstamp']];
421
422 87
        if ($itemTypeHasStartTimeColumn) {
423 87
            $startTime = $record[$GLOBALS['TCA'][$itemType]['ctrl']['enablecolumns']['starttime']];
424
        }
425
426 87
        if ($itemType === 'pages') {
427 59
            $record['uid'] = $itemUid;
428
            // overrule the page's last changed time with the most recent
429
            //content element change
430 59
            $pageChangedTime = $this->getPageItemChangedTime($record);
0 ignored issues
show
Bug introduced by
It seems like $record can also be of type null; however, parameter $page of ApacheSolrForTypo3\Solr\...etPageItemChangedTime() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

430
            $pageChangedTime = $this->getPageItemChangedTime(/** @scrutinizer ignore-type */ $record);
Loading history...
431
        }
432
433 87
        $localizationsChangedTime = $this->queueItemRepository->getLocalizableItemChangedTime($itemType, (int)$itemUid);
434
435
        // if start time exists and start time is higher than last changed timestamp
436
        // then set changed to the future start time to make the item
437
        // indexed at a later time
438 87
        return (int)max(
439 87
            $itemChangedTime,
440 87
            $pageChangedTime,
441 87
            $localizationsChangedTime,
442 87
            $startTime
443 87
        );
444
    }
445
446
    /**
447
     * Gets the most recent changed time of a page's content elements
448
     *
449
     * @param array $page Partial page record
450
     * @return int Timestamp of the most recent content element change
451
     * @throws DBALDriverException
452
     * @throws DBALException|\Doctrine\DBAL\DBALException
453
     */
454 59
    protected function getPageItemChangedTime(array $page): int
455
    {
456 59
        if (!empty($page['content_from_pid'])) {
457
            // canonical page, get the original page's last changed time
458
            return $this->queueItemRepository->getPageItemChangedTimeByPageUid((int)$page['content_from_pid']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->queueItemR...ge['content_from_pid']) could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
459
        }
460 59
        return $this->queueItemRepository->getPageItemChangedTimeByPageUid((int)$page['uid']) ?? 0;
461
    }
462
463
    /**
464
     * Checks whether the Index Queue contains a specific item.
465
     *
466
     * @param string $itemType The item's type, usually a table name.
467
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
468
     *      different value for non-database-record types.
469
     * @return bool TRUE if the item is found in the queue, FALSE otherwise
470
     * @throws DBALDriverException
471
     * @throws DBALException|\Doctrine\DBAL\DBALException
472
     */
473 10
    public function containsItem(string $itemType, $itemUid): bool
474
    {
475 10
        return $this->queueItemRepository->containsItem($itemType, (int)$itemUid);
476
    }
477
478
    /**
479
     * Checks whether the Index Queue contains a specific item.
480
     *
481
     * @param string $itemType The item's type, usually a table name.
482
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
483
     *      different value for non-database-record types.
484
     * @param int $rootPageId
485
     * @return bool TRUE if the item is found in the queue, FALSE otherwise
486
     * @throws DBALDriverException
487
     * @throws DBALException|\Doctrine\DBAL\DBALException
488
     */
489 87
    public function containsItemWithRootPageId(string $itemType, $itemUid, int $rootPageId): bool
490
    {
491 87
        return $this->queueItemRepository->containsItemWithRootPageId($itemType, (int)$itemUid, $rootPageId);
492
    }
493
494
    /**
495
     * Checks whether the Index Queue contains a specific item that has been
496
     * marked as indexed.
497
     *
498
     * @param string $itemType The item's type, usually a table name.
499
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a
500
     *      different value for non-database-record types.
501
     * @return bool TRUE if the item is found in the queue and marked as
502
     *      indexed, FALSE otherwise
503
     * @throws DBALDriverException
504
     * @throws DBALException|\Doctrine\DBAL\DBALException
505
     */
506 4
    public function containsIndexedItem(string $itemType, $itemUid): bool
507
    {
508 4
        return $this->queueItemRepository->containsIndexedItem($itemType, (int)$itemUid);
509
    }
510
511
    /**
512
     * Removes an item from the Index Queue.
513
     *
514
     * @param string $itemType The type of the item to remove, usually a table name.
515
     * @param int|string $itemUid The uid of the item to remove
516
     * @throws ConnectionException
517
     * @throws DBALException
518
     * @throws Throwable
519
     */
520 61
    public function deleteItem(string $itemType, $itemUid)
521
    {
522 61
        $this->queueItemRepository->deleteItem($itemType, (int)$itemUid);
523
    }
524
525
    /**
526
     * Removes all items of a certain type from the Index Queue.
527
     *
528
     * @param string $itemType The type of items to remove, usually a table name.
529
     * @throws ConnectionException
530
     * @throws DBALException
531
     * @throws Throwable
532
     */
533 1
    public function deleteItemsByType(string $itemType)
534
    {
535 1
        $this->queueItemRepository->deleteItemsByType($itemType);
536
    }
537
538
    /**
539
     * Removes all items of a certain site from the Index Queue. Accepts an
540
     * optional parameter to limit the deleted items by indexing configuration.
541
     *
542
     * @param Site $site The site to remove items for.
543
     * @param string $indexingConfigurationName Name of a specific indexing
544
     *      configuration
545
     * @throws ConnectionException
546
     * @throws \Doctrine\DBAL\DBALException
547
     * @throws Throwable
548
     */
549 6
    public function deleteItemsBySite(Site $site, string $indexingConfigurationName = '')
550
    {
551 6
        $this->queueItemRepository->deleteItemsBySite($site, $indexingConfigurationName);
552
    }
553
554
    /**
555
     * Removes all items from the Index Queue.
556
     */
557 1
    public function deleteAllItems()
558
    {
559 1
        $this->queueItemRepository->deleteAllItems();
560
    }
561
562
    /**
563
     * Gets a single Index Queue item by its uid.
564
     *
565
     * @param int $itemId Index Queue item uid
566
     * @return Item|null The request Index Queue item or NULL if no item with $itemId was found
567
     * @throws DBALDriverException
568
     * @throws DBALException|\Doctrine\DBAL\DBALException
569
     */
570 34
    public function getItem(int $itemId): ?Item
571
    {
572 34
        return $this->queueItemRepository->findItemByUid($itemId);
573
    }
574
575
    /**
576
     * Gets Index Queue items by type and uid.
577
     *
578
     * @param string $itemType item type, usually  the table name
579
     * @param int|string $itemUid item uid
580
     * @return Item[] An array of items matching $itemType and $itemUid
581
     * @throws ConnectionException
582
     * @throws DBALDriverException
583
     * @throws DBALException
584
     * @throws Throwable
585
     */
586 52
    public function getItems(string $itemType, $itemUid): array
587
    {
588 52
        return $this->queueItemRepository->findItemsByItemTypeAndItemUid($itemType, (int)$itemUid);
589
    }
590
591
    /**
592
     * Returns all items in the queue.
593
     *
594
     * @return Item[] An array of items
595
     * @throws ConnectionException
596
     * @throws DBALDriverException
597
     * @throws DBALException
598
     * @throws Throwable
599
     */
600 4
    public function getAllItems(): array
601
    {
602 4
        return $this->queueItemRepository->findAll();
603
    }
604
605
    /**
606
     * Returns the number of items for all queues.
607
     *
608
     * @return int
609
     * @throws DBALDriverException
610
     * @throws DBALException
611
     */
612 112
    public function getAllItemsCount(): int
613
    {
614 112
        return $this->queueItemRepository->count();
615
    }
616
617
    /**
618
     * Extracts the number of pending, indexed and erroneous items from the
619
     * Index Queue.
620
     *
621
     * @param Site $site
622
     * @param string $indexingConfigurationName
623
     *
624
     * @return QueueStatistic
625
     * @throws DBALDriverException
626
     * @throws DBALException
627
     */
628 5
    public function getStatisticsBySite(Site $site, string $indexingConfigurationName = ''): QueueStatistic
629
    {
630 5
        return $this->queueStatisticsRepository
631 5
            ->findOneByRootPidAndOptionalIndexingConfigurationName(
632 5
                $site->getRootPageId(),
633 5
                $indexingConfigurationName
634 5
            );
635
    }
636
637
    /**
638
     * Gets $limit number of items to index for a particular $site.
639
     *
640
     * @param Site $site TYPO3 site
641
     * @param int $limit Number of items to get from the queue
642
     * @return Item[] Items to index to the given solr server
643
     * @throws ConnectionException
644
     * @throws DBALDriverException
645
     * @throws DBALException
646
     * @throws Throwable
647
     */
648 3
    public function getItemsToIndex(Site $site, int $limit = 50): array
649
    {
650 3
        return $this->queueItemRepository->findItemsToIndex($site, $limit);
651
    }
652
653
    /**
654
     * Marks an item as failed and causes the indexer to skip the item in the
655
     * next run.
656
     *
657
     * @param int|Item $item Either the item's Index Queue uid or the complete item
658
     * @param string $errorMessage Error message
659
     * @throws DBALException|\Doctrine\DBAL\DBALException
660
     */
661 6
    public function markItemAsFailed($item, string $errorMessage = '')
662
    {
663 6
        $this->queueItemRepository->markItemAsFailed($item, $errorMessage);
664
    }
665
666
    /**
667
     * Sets the timestamp of when an item last has been indexed.
668
     *
669
     * @param Item $item
670
     * @throws DBALException|\Doctrine\DBAL\DBALException
671
     */
672 2
    public function updateIndexTimeByItem(Item $item)
673
    {
674 2
        $this->queueItemRepository->updateIndexTimeByItem($item);
675
    }
676
677
    /**
678
     * Sets the change timestamp of an item.
679
     *
680
     * @param Item $item
681
     * @param int $forcedChangeTime The change time for the item
682
     * @throws DBALException|\Doctrine\DBAL\DBALException
683
     */
684
    public function setForcedChangeTimeByItem(Item $item, int $forcedChangeTime = 0)
685
    {
686
        $this->queueItemRepository->updateChangedTimeByItem($item, $forcedChangeTime);
687
    }
688
}
689