Passed
Pull Request — main (#3444)
by Markus
29:09
created

Queue::updateOrAddItemForAllRelatedRootPages()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 38
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 7.0084

Importance

Changes 0
Metric Value
eloc 24
c 0
b 0
f 0
dl 0
loc 38
ccs 17
cts 18
cp 0.9444
rs 8.6026
cc 7
nc 7
nop 3
crap 7.0084
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\Exception\RootPageRecordNotFoundException;
23
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\ConfigurationAwareRecordService;
24
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\RootPageResolver;
25
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\Statistic\QueueStatistic;
26
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\Statistic\QueueStatisticsRepository;
27
use ApacheSolrForTypo3\Solr\Domain\Site\Site;
28
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
29
use ApacheSolrForTypo3\Solr\FrontendEnvironment;
30
use ApacheSolrForTypo3\Solr\System\Cache\TwoLevelCache;
31
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
32
use Doctrine\DBAL\ConnectionException;
33
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
34
use Doctrine\DBAL\Exception as DBALException;
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 153
     */
90
    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 153
    ) {
98 153
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
99 153
        $this->rootPageResolver = $rootPageResolver ?? GeneralUtility::makeInstance(RootPageResolver::class);
100 153
        $this->recordService = $recordService ?? GeneralUtility::makeInstance(ConfigurationAwareRecordService::class);
101 153
        $this->queueItemRepository = $queueItemRepository ?? GeneralUtility::makeInstance(QueueItemRepository::class);
102 153
        $this->queueStatisticsRepository = $queueStatisticsRepository ??  GeneralUtility::makeInstance(QueueStatisticsRepository::class);
103 153
        $this->queueInitializationService = $queueInitializationService ?? GeneralUtility::makeInstance(QueueInitializationService::class, /** @scrutinizer ignore-type */ $this);
104
        $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 2
     */
119
    public function getLastIndexTime(int $rootPageId): int
120 2
    {
121
        $lastIndexTime = 0;
122 2
123
        $lastIndexedRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
124 2
125 1
        if ($lastIndexedRow[0]['indexed']) {
126
            $lastIndexTime = $lastIndexedRow[0]['indexed'];
127
        }
128 2
129
        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 3
     */
141
    public function getLastIndexedItemId(int $rootPageId): int
142 3
    {
143
        $lastIndexedItemId = 0;
144 3
145 3
        $lastIndexedItemRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
146 2
        if ($lastIndexedItemRow[0]['uid']) {
147
            $lastIndexedItemId = $lastIndexedItemRow[0]['uid'];
148
        }
149 3
150
        return $lastIndexedItemId;
151
    }
152
153
    /**
154
     * @return QueueInitializationService
155 6
     */
156
    public function getInitializationService(): QueueInitializationService
157 6
    {
158
        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 91
     */
177
    public function updateItem(string $itemType, $itemUid, int $forcedChangeTime = 0): int
178 91
    {
179 90
        $updateCount = $this->updateOrAddItemForAllRelatedRootPages($itemType, $itemUid, $forcedChangeTime);
180
        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 89
     */
194
    protected function updateOrAddItemForAllRelatedRootPages(string $itemType, $itemUid, int $forcedChangeTime): int
195 89
    {
196 89
        $updateCount = 0;
197 88
        try {
198 88
            $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 88
        } catch (RootPageRecordNotFoundException $e) {
200
            $this->deleteItem($itemType, $itemUid);
201
            return 0;
202
        }
203
204 88
        foreach ($rootPageIds as $rootPageId) {
205 88
            $skipInvalidRootPage = $rootPageId === 0;
206 88
            if ($skipInvalidRootPage) {
207 88
                continue;
208 3
            }
209
210 87
            /* @var SiteRepository $siteRepository */
211 87
            $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
212
            $solrConfiguration = $siteRepository->getSiteByRootPageId($rootPageId)->getSolrConfiguration();
213 19
            $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

213
            $indexingConfiguration = $this->recordService->getIndexingConfigurationName($itemType, /** @scrutinizer ignore-type */ $itemUid, $solrConfiguration);
Loading history...
214 19
            if ($indexingConfiguration === null) {
215
                continue;
216
            }
217 80
            $indexingPriority = $solrConfiguration->getIndexQueueIndexingPriorityByConfigurationName($indexingConfiguration);
218
            $itemInQueueForRootPage = $this->containsItemWithRootPageId($itemType, $itemUid, $rootPageId);
219
            if ($itemInQueueForRootPage) {
220 87
                // update changed time if that item is in the queue already
221
                $changedTime = ($forcedChangeTime > 0) ? $forcedChangeTime : $this->getItemChangedTime($itemType, $itemUid);
222
                $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

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

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

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