Passed
Pull Request — main (#3509)
by
unknown
31:44
created

Queue::updateOrAddItemForAllRelatedRootPages()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 6.0045

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 32
ccs 19
cts 20
cp 0.95
rs 8.9777
c 0
b 0
f 0
cc 6
nc 6
nop 3
crap 6.0045
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 Throwable;
35
use TYPO3\CMS\Backend\Utility\BackendUtility;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
38
/**
39
 * The Indexing Queue. It allows us to decouple from frontend indexing and
40
 * reacting to the changes faster.
41
 *
42
 * @author Ingo Renner <[email protected]>
43
 */
44
class Queue
45
{
46
    /**
47
     * @var RootPageResolver
48
     */
49
    protected RootPageResolver $rootPageResolver;
50
51
    /**
52
     * @var ConfigurationAwareRecordService
53
     */
54
    protected ConfigurationAwareRecordService $recordService;
55
56
    /**
57
     * @var SolrLogManager
58
     */
59
    protected SolrLogManager $logger;
60
61
    /**
62
     * @var QueueItemRepository
63
     */
64
    protected QueueItemRepository $queueItemRepository;
65
66
    /**
67
     * @var QueueStatisticsRepository
68
     */
69
    protected QueueStatisticsRepository $queueStatisticsRepository;
70
71
    /**
72
     * @var QueueInitializationService
73
     */
74
    protected QueueInitializationService $queueInitializationService;
75
76
    /**
77
     * @var FrontendEnvironment
78
     */
79
    protected FrontendEnvironment $frontendEnvironment;
80
81
    /**
82
     * Queue constructor.
83
     * @param RootPageResolver|null $rootPageResolver
84
     * @param ConfigurationAwareRecordService|null $recordService
85
     * @param QueueItemRepository|null $queueItemRepository
86
     * @param QueueStatisticsRepository|null $queueStatisticsRepository
87
     * @param QueueInitializationService|null $queueInitializationService
88
     */
89 153
    public function __construct(
90
        RootPageResolver $rootPageResolver = null,
91
        ConfigurationAwareRecordService $recordService = null,
92
        QueueItemRepository $queueItemRepository = null,
93
        QueueStatisticsRepository $queueStatisticsRepository = null,
94
        QueueInitializationService $queueInitializationService = null,
95
        FrontendEnvironment $frontendEnvironment = null
96
    ) {
97 153
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
98 153
        $this->rootPageResolver = $rootPageResolver ?? GeneralUtility::makeInstance(RootPageResolver::class);
99 153
        $this->recordService = $recordService ?? GeneralUtility::makeInstance(ConfigurationAwareRecordService::class);
100 153
        $this->queueItemRepository = $queueItemRepository ?? GeneralUtility::makeInstance(QueueItemRepository::class);
101 153
        $this->queueStatisticsRepository = $queueStatisticsRepository ??  GeneralUtility::makeInstance(QueueStatisticsRepository::class);
102 153
        $this->queueInitializationService = $queueInitializationService ?? GeneralUtility::makeInstance(QueueInitializationService::class, /** @scrutinizer ignore-type */ $this);
103 153
        $this->frontendEnvironment = $frontendEnvironment ?? GeneralUtility::makeInstance(FrontendEnvironment::class);
104
    }
105
106
    // FIXME some of the methods should be renamed to plural forms
107
    // FIXME singular form methods should deal with exactly one item only
108
109
    /**
110
     * Returns the timestamp of the last indexing run.
111
     *
112
     * @param int $rootPageId The root page uid for which to get
113
     *      the last indexed item id
114
     * @return int Timestamp of last index run.
115
     * @throws DBALDriverException
116
     * @throws DBALException|\Doctrine\DBAL\DBALException
117
     */
118 2
    public function getLastIndexTime(int $rootPageId): int
119
    {
120 2
        $lastIndexTime = 0;
121
122 2
        $lastIndexedRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
123
124 2
        if ($lastIndexedRow[0]['indexed']) {
125 1
            $lastIndexTime = $lastIndexedRow[0]['indexed'];
126
        }
127
128 2
        return $lastIndexTime;
129
    }
130
131
    /**
132
     * Returns the uid of the last indexed item in the queue
133
     *
134
     * @param int $rootPageId The root page uid for which to get
135
     *      the last indexed item id
136
     * @return int The last indexed item's ID.
137
     * @throws DBALDriverException
138
     * @throws DBALException|\Doctrine\DBAL\DBALException
139
     */
140 3
    public function getLastIndexedItemId(int $rootPageId): int
141
    {
142 3
        $lastIndexedItemId = 0;
143
144 3
        $lastIndexedItemRow = $this->queueItemRepository->findLastIndexedRow($rootPageId);
145 3
        if ($lastIndexedItemRow[0]['uid']) {
146 2
            $lastIndexedItemId = $lastIndexedItemRow[0]['uid'];
147
        }
148
149 3
        return $lastIndexedItemId;
150
    }
151
152
    /**
153
     * @return QueueInitializationService
154
     */
155 6
    public function getInitializationService(): QueueInitializationService
156
    {
157 6
        return $this->queueInitializationService;
158
    }
159
160
    /**
161
     * Marks an item as needing (re)indexing.
162
     *
163
     * Like with Solr itself, there's no add method, just a simple update method
164
     * that handles the adds, too.
165
     *
166
     * The method creates or updates the index queue items for all related rootPageIds.
167
     *
168
     * @param string $itemType The item's type, usually a table name.
169
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
170
     * @param int $forcedChangeTime The change time for the item if set, otherwise value from getItemChangedTime() is used.
171
     * @return int Number of updated/created items
172
     * @throws DBALDriverException
173
     * @throws DBALException|\Doctrine\DBAL\DBALException
174
     * @throws Throwable
175
     */
176 91
    public function updateItem(string $itemType, $itemUid, int $forcedChangeTime = 0): int
177
    {
178 91
        $updateCount = $this->updateOrAddItemForAllRelatedRootPages($itemType, $itemUid, $forcedChangeTime);
179 90
        return $this->postProcessIndexQueueUpdateItem($itemType, $itemUid, $updateCount, $forcedChangeTime);
180
    }
181
182
    /**
183
     * Updates or adds the item for all relevant root pages.
184
     *
185
     * @param string $itemType The item's type, usually a table name.
186
     * @param int|string $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
187
     * @param int $forcedChangeTime The change time for the item if set, otherwise value from getItemChangedTime() is used.
188
     * @return int
189
     * @throws DBALDriverException
190
     * @throws DBALException|\Doctrine\DBAL\DBALException
191
     * @throws Throwable
192
     */
193 89
    protected function updateOrAddItemForAllRelatedRootPages(string $itemType, $itemUid, int $forcedChangeTime): int
194
    {
195 89
        $updateCount = 0;
196 89
        $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

196
        $rootPageIds = $this->rootPageResolver->getResponsibleRootPageIds($itemType, /** @scrutinizer ignore-type */ $itemUid);
Loading history...
197 88
        foreach ($rootPageIds as $rootPageId) {
198 88
            $skipInvalidRootPage = $rootPageId === 0;
199 88
            if ($skipInvalidRootPage) {
200
                continue;
201
            }
202
203
            /* @var SiteRepository $siteRepository */
204 88
            $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
205 88
            $solrConfiguration = $siteRepository->getSiteByRootPageId($rootPageId)->getSolrConfiguration();
206 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

206
            $indexingConfiguration = $this->recordService->getIndexingConfigurationName($itemType, /** @scrutinizer ignore-type */ $itemUid, $solrConfiguration);
Loading history...
207 88
            if ($indexingConfiguration === null) {
208 3
                continue;
209
            }
210 87
            $indexingPriority = $solrConfiguration->getIndexQueueIndexingPriorityByConfigurationName($indexingConfiguration);
211 87
            $itemInQueueForRootPage = $this->containsItemWithRootPageId($itemType, $itemUid, $rootPageId);
212 87
            if ($itemInQueueForRootPage) {
213
                // update changed time if that item is in the queue already
214 19
                $changedTime = ($forcedChangeTime > 0) ? $forcedChangeTime : $this->getItemChangedTime($itemType, $itemUid);
215 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

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

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

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