Passed
Pull Request — master (#1587)
by Rafael
05:25
created

getPageItemChangedTimeByPageUid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 1
1
<?php declare(strict_types = 1);
2
namespace ApacheSolrForTypo3\Solr\Domain\Index\Queue;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2010-2017 dkd Internet Service GmbH <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\IndexQueue\Item;
28
use ApacheSolrForTypo3\Solr\Site;
29
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
30
use ApacheSolrForTypo3\Solr\System\Records\AbstractRepository;
31
use TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression;
32
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
33
use TYPO3\CMS\Core\Utility\GeneralUtility;
34
35
/**
36
 * Class QueueItemRepository
37
 * Handles all CRUD operations to tx_solr_indexqueue_item table
38
 *
39
 */
40
class QueueItemRepository extends AbstractRepository
41
{
42
    /**
43
     * @var string
44
     */
45
    protected $table = 'tx_solr_indexqueue_item';
46
47
    /**
48
     * @var SolrLogManager
49
     */
50
    protected $logger;
51
52
    /**
53
     * QueueItemRepository constructor.
54
     *
55
     * @param SolrLogManager|null $logManager
56
     */
57
    public function __construct(SolrLogManager $logManager = null)
58
    {
59
        $this->logger = isset($logManager) ? $logManager : GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
60
    }
61
62
    /**
63
     * Fetches the last indexed row
64
     *
65
     * @param int $rootPageId The root page uid for which to get the last indexed row
66
     * @return array
67
     */
68
    public function findLastIndexedRow(int $rootPageId) : array
69
    {
70
        $queryBuilder = $this->getQueryBuilder();
71
        $row = $queryBuilder
72
            ->select('uid', 'indexed')
73
            ->from($this->table)
74
            ->where($queryBuilder->expr()->eq('root', $rootPageId))
75
            ->andWhere($queryBuilder->expr()->neq('indexed', 0))
76
            ->orderBy('indexed', 'DESC')
77
            ->setMaxResults(1)
78
            ->execute()->fetchAll();
79
80
        return $row;
81
    }
82
83
    /**
84
     * Finds indexing errors for the current site
85
     *
86
     * @param Site $site
87
     * @return array Error items for the current site's Index Queue
88
     */
89
    public function findErrorsBySite(Site $site) : array
90
    {
91
        $queryBuilder = $this->getQueryBuilder();
92
        $errors = $queryBuilder
93
            ->select('uid', 'item_type', 'item_uid', 'errors')
94
            ->from($this->table)
95
            ->andWhere(
96
                $queryBuilder->expr()->notLike('errors', $queryBuilder->createNamedParameter('')),
97
                $queryBuilder->expr()->eq('root', $site->getRootPageId())
98
            )
99
            ->execute()->fetchAll();
100
101
        return $errors;
102
    }
103
104
    /**
105
     * Resets all the errors for all index queue items.
106
     *
107
     * @return int affected rows
108
     */
109
    public function flushAllErrors() : int
110
    {
111
        $queryBuilder = $this->getQueryBuilder();
112
        $affectedRows = $queryBuilder
113
            ->update($this->table)
114
            ->set('errors', '')
115
            ->where(
116
                $queryBuilder->expr()->notLike('errors', $queryBuilder->createNamedParameter(''))
117
            )
118
            ->execute();
119
        return $affectedRows;
120
    }
121
122
    /**
123
     * Updates an existing queue entry by $itemType $itemUid and $rootPageId.
124
     *
125
     * @param string $itemType The item's type, usually a table name.
126
     * @param int $itemUid The item's uid, usually an integer uid, could be a
127
     *      different value for non-database-record types.
128
     * @param string $indexingConfiguration The name of the related indexConfiguration
129
     * @param int $rootPageId The uid of the rootPage
130
     * @param int $changedTime The forced change time that should be used for updating
131
     * @return int affected rows
132
     */
133
    public function updateExistingItemByItemTypeAndItemUidAndRootPageId(string $itemType, int $itemUid, int $rootPageId, int $changedTime, string $indexingConfiguration = '') : int
134
    {
135
        $queryBuilder = $this->getQueryBuilder();
136
        $queryBuilder
137
            ->update($this->table)
138
            ->set('changed', $changedTime)
139
            ->andWhere(
140
                $queryBuilder->expr()->eq('item_type', $queryBuilder->createNamedParameter($itemType)),
141
                $queryBuilder->expr()->eq('item_uid', $itemUid),
142
                $queryBuilder->expr()->eq('root', $rootPageId)
143
            );
144
145
        if (!empty($indexingConfiguration)) {
146
            $queryBuilder->set('indexing_configuration', $indexingConfiguration);
147
        }
148
149
        return $queryBuilder->execute();
150
    }
151
152
    /**
153
     * Adds an item to the index queue.
154
     *
155
     * Not meant for public use.
156
     *
157
     * @param string $itemType The item's type, usually a table name.
158
     * @param int $itemUid The item's uid, usually an integer uid, could be a different value for non-database-record types.
159
     * @param int $rootPageId
160
     * @param int $changedTime
161
     * @param string $indexingConfiguration The item's indexing configuration to use. Optional, overwrites existing / determined configuration.
162
     * @return int the number of inserted rows, which is typically 1
163
     */
164
    public function add(string $itemType, int $itemUid, int $rootPageId, int $changedTime, string $indexingConfiguration) : int
165
    {
166
        $queryBuilder = $this->getQueryBuilder();
167
        return $queryBuilder
168
            ->insert($this->table)
169
            ->values([
170
                'root' => $rootPageId,
171
                'item_type' => $itemType,
172
                'item_uid' => $itemUid,
173
                'changed' => $changedTime,
174
                'errors' => '',
175
                'indexing_configuration' => $indexingConfiguration
176
            ])
177
            ->execute();
178
179
    }
180
181
    /**
182
     * Gets the most recent changed time of a page's content elements
183
     *
184
     * @param int $pageUid
185
     * @return int|null Timestamp of the most recent content element change or null if nothing is found.
186
     */
187
    public function getPageItemChangedTimeByPageUid(int $pageUid)
188
    {
189
        $queryBuilder = $this->getQueryBuilder();
190
        $queryBuilder->getRestrictions()->removeAll();
191
        $pageContentLastChangedTime = $queryBuilder
192
            ->add('select', $queryBuilder->expr()->max('tstamp', 'changed_time'))
193
            ->from('tt_content')
194
            ->where(
195
                $queryBuilder->expr()->eq('pid', $pageUid)
196
            )
197
            ->execute()->fetch();
198
199
        return $pageContentLastChangedTime['changed_time'];
200
    }
201
202
    /**
203
     * Gets the most recent changed time for an item taking into account
204
     * localized records.
205
     *
206
     * @param string $itemType The item's type, usually a table name.
207
     * @param int $itemUid The item's uid
208
     * @return int Timestamp of the most recent content element change
209
     */
210
    public function getLocalizableItemChangedTime(string $itemType, int $itemUid) : int
211
    {
212
        $localizedChangedTime = 0;
213
214
        if ($itemType === 'pages') {
215
            $itemType = 'pages_language_overlay';
216
        }
217
218
        if (isset($GLOBALS['TCA'][$itemType]['ctrl']['transOrigPointerField'])) {
219
            // table is localizable
220
            $translationOriginalPointerField = $GLOBALS['TCA'][$itemType]['ctrl']['transOrigPointerField'];
221
222
            $queryBuilder = $this->getQueryBuilder();
223
            $queryBuilder->getRestrictions()->removeAll();
224
            $localizedChangedTime = $queryBuilder
225
                ->add('select', $queryBuilder->expr()->max('tstamp', 'changed_time'))
226
                ->from($itemType)
227
                ->orWhere(
228
                    $queryBuilder->expr()->eq('uid', $itemUid),
229
                    $queryBuilder->expr()->eq($translationOriginalPointerField, $itemUid)
230
                )->execute()->fetchColumn(0);
231
        }
232
233
        return (int)$localizedChangedTime;
234
    }
235
236
    /**
237
     * Returns prepared QueryBuilder for contains* methods in this repository
238
     *
239
     * @param string $itemType
240
     * @param int $itemUid
241
     * @return QueryBuilder
242
     */
243
    protected function getQueryBuilderForContainsMethods(string $itemType, int $itemUid) : QueryBuilder
244
    {
245
        $queryBuilder = $this->getQueryBuilder();
246
        return $queryBuilder->count('uid')->from($this->table)
247
            ->andWhere(
248
                $queryBuilder->expr()->eq('item_type', $queryBuilder->createNamedParameter($itemType)),
249
                $queryBuilder->expr()->eq('item_uid', $itemUid)
250
            );
251
    }
252
253
    /**
254
     * Checks whether the Index Queue contains a specific item.
255
     *
256
     * @param string $itemType The item's type, usually a table name.
257
     * @param int $itemUid The item's uid
258
     * @return bool TRUE if the item is found in the queue, FALSE otherwise
259
     */
260
    public function containsItem(string $itemType, int $itemUid) : bool
261
    {
262
        return (bool)$this->getQueryBuilderForContainsMethods($itemType, $itemUid)->execute()->fetchColumn(0);
263
    }
264
265
    /**
266
     * Checks whether the Index Queue contains a specific item.
267
     *
268
     * @param string $itemType The item's type, usually a table name.
269
     * @param int $itemUid The item's uid
270
     * @param integer $rootPageId
271
     * @return bool TRUE if the item is found in the queue, FALSE otherwise
272
     */
273
    public function containsItemWithRootPageId(string $itemType, int $itemUid, int $rootPageId) : bool
274
    {
275
        $queryBuilder = $this->getQueryBuilderForContainsMethods($itemType, $itemUid);
276
        return (bool)$queryBuilder
277
            ->andWhere($queryBuilder->expr()->eq('root', $rootPageId))
278
            ->execute()->fetchColumn(0);
279
    }
280
281
    /**
282
     * Checks whether the Index Queue contains a specific item that has been
283
     * marked as indexed.
284
     *
285
     * @param string $itemType The item's type, usually a table name.
286
     * @param int $itemUid The item's uid
287
     * @return bool TRUE if the item is found in the queue and marked as
288
     *      indexed, FALSE otherwise
289
     */
290
    public function containsIndexedItem(string $itemType, int $itemUid) : bool
291
    {
292
        $queryBuilder = $this->getQueryBuilderForContainsMethods($itemType, $itemUid);
293
        return (bool)$queryBuilder
294
            ->andWhere($queryBuilder->expr()->gt('indexed', 0))
295
            ->execute()->fetchColumn(0);
296
    }
297
298
    /**
299
     * Returns the list with Uids to delete by given item type and optional item Uid
300
     *
301
     * @param string $itemType The item's type, usually a table name.
302
     * @param int|null $itemUid The item's uid
303
     * @return array the list with item Uids to delete
304
     */
305
    protected function getItemListToDeleteByItemTypeAndOptionalItemUid(string $itemType, int $itemUid = null) : array
306
    {
307
        $queryBuilderForItemListToDelete = $this->getQueryBuilder();
308
        $queryBuilderForItemListToDelete
309
            ->select('uid')
310
            ->from($this->table)
311
            ->andWhere(
312
                $queryBuilderForItemListToDelete->expr()->eq('item_type', $queryBuilderForItemListToDelete->createNamedParameter($itemType))
313
            );
314
315
        if (isset($itemUid)) {
316
            $queryBuilderForItemListToDelete->andWhere($queryBuilderForItemListToDelete->expr()->eq('item_uid', $itemUid));
317
        }
318
319
        return $queryBuilderForItemListToDelete->execute()->fetchAll(\PDO::FETCH_COLUMN);
320
    }
321
322
    /**
323
     * Removes an item from the Index Queue.
324
     *
325
     * @todo: use transaction
326
     *        use sub-select for tx_solr_indexqueue_indexing_property IN() clause and native WHERE clause for tx_solr_indexqueue_item instead of fetching and concat it with PHP
327
     * @param string $itemType The type of the item to remove, usually a table name.
328
     * @param int $itemUid The uid of the item to remove
329
     */
330
    public function deleteItem(string $itemType, int $itemUid = null)
331
    {
332
        $items = $this->getItemListToDeleteByItemTypeAndOptionalItemUid($itemType, $itemUid);
333
        if (empty($items)) {
334
            return;
335
        }
336
337
        $queryBuilder = $this->getQueryBuilder();
338
        $queryBuilder
339
            ->delete($this->table)
340
            ->where(
341
                $queryBuilder->expr()->in('uid', $items)
342
            )
343
            ->execute();
344
345
        $queryBuilder2 = $this->getQueryBuilder();
346
        $queryBuilder2
347
            ->delete('tx_solr_indexqueue_indexing_property')
348
            ->where(
349
                $queryBuilder2->expr()->in('uid', $items)
350
            )
351
            ->execute();
352
    }
353
354
    /**
355
     * Removes all items of a certain type from the Index Queue.
356
     *
357
     * @param string $itemType The type of items to remove, usually a table name.
358
     */
359
    public function deleteItemsByType(string $itemType)
360
    {
361
        $this->deleteItem($itemType);
362
    }
363
364
    /**
365
     * Removes all items of a certain site from the Index Queue. Accepts an
366
     * optional parameter to limit the deleted items by indexing configuration.
367
     *
368
     * @param Site $site The site to remove items for.
369
     * @param string $indexingConfigurationName Name of a specific indexing configuration
370
     * @throws \Exception
371
     */
372
    public function deleteItemsBySite(Site $site, string $indexingConfigurationName = '')
373
    {
374
        $queryBuilderForDeletingItems = $this->getQueryBuilder();
375
        $queryBuilderForDeletingItems
376
            ->delete($this->table)
377
            ->where($queryBuilderForDeletingItems->expr()->eq('root', $site->getRootPageId()));
378
        if (!empty($indexingConfigurationName)) {
379
            $queryBuilderForDeletingItems->andWhere($queryBuilderForDeletingItems->expr()->eq('indexing_configuration', $queryBuilderForDeletingItems->createNamedParameter($indexingConfigurationName)));
380
        }
381
382
        $queryBuilderForDeletingProperties = $queryBuilderForDeletingItems->getConnection()->createQueryBuilder();
383
        $queryBuilderForDeletingProperties
384
            ->delete('tx_solr_indexqueue_indexing_property')
385
            ->innerJoin(
386
                'properties',
387
                $this->table,
388
                'items',
389
                (string)$queryBuilderForDeletingProperties->expr()->andX(
390
                    $queryBuilderForDeletingProperties->expr()->eq('items.uid', $queryBuilderForDeletingProperties->quoteIdentifier('properties.item_id')),
391
                    $queryBuilderForDeletingProperties->expr()->eq('items.root' , $site->getRootPageId()),
392
                    empty($indexingConfigurationName) ? '' : $queryBuilderForDeletingProperties->expr()->eq(
393
                        'items.indexing_configuration', $queryBuilderForDeletingProperties->createNamedParameter($indexingConfigurationName)
394
                    )
395
                )
396
            );
397
398
        $queryBuilderForDeletingItems->getConnection()->beginTransaction();
399
        try {
400
            $queryBuilderForDeletingItems->execute();
401
            $queryBuilderForDeletingProperties->execute();
402
403
            $queryBuilderForDeletingItems->getConnection()->commit();
404
        } catch (\Exception $e) {
405
            $queryBuilderForDeletingItems->getConnection()->rollback();
406
            throw $e;
407
        }
408
    }
409
410
    /**
411
     * Removes all items from the Index Queue.
412
     *
413
     * @return int The number of affected rows. For a truncate this is unreliable as theres no meaningful information.
414
     */
415
    public function deleteAllItems()
416
    {
417
        return $this->getQueryBuilder()->getConnection()->truncate($this->table);
418
    }
419
420
    /**
421
     * Gets a single Index Queue item by its uid.
422
     *
423
     * @param int $uid Index Queue item uid
424
     * @return Item|null The request Index Queue item or NULL if no item with $itemId was found
425
     */
426
    public function findItemByUid(int $uid)
427
    {
428
        $queryBuilder = $this->getQueryBuilder();
429
        $indexQueueItemRecord = $queryBuilder
430
            ->select('*')
431
            ->from($this->table)
432
            ->where($queryBuilder->expr()->eq('uid', $uid))
433
            ->execute()->fetch();
434
435
        if (!isset($indexQueueItemRecord['uid'])) {
436
            return null;
437
        }
438
439
        /** @var Item $item*/
440
        $item = GeneralUtility::makeInstance(Item::class, $indexQueueItemRecord);
441
        return $item;
442
    }
443
444
    /**
445
     * Gets Index Queue items by type and uid.
446
     *
447
     * @param string $itemType item type, usually  the table name
448
     * @param int $itemUid item uid
449
     * @return Item[] An array of items matching $itemType and $itemUid
450
     */
451
    public function findItemsByItemTypeAndItemUid(string $itemType, int $itemUid) : array
452
    {
453
        $queryBuilder = $this->getQueryBuilder();
454
        $compositeExpression = $queryBuilder->expr()->andX(
455
            $queryBuilder->expr()->eq('item_type', $queryBuilder->getConnection()->quote($itemType, \PDO::PARAM_STR)),
456
            $queryBuilder->expr()->eq('item_uid', $itemUid)
457
        );
458
        return $this->getItemsByCompositeExpression($compositeExpression, $queryBuilder);
459
    }
460
461
    /**
462
     * Returns a collection of items by CompositeExpression.
463
     * D
464
     *
465
     * @param CompositeExpression|null $expression Optional expression to filter records.
466
     * @param QueryBuilder|null $queryBuilder QueryBuilder to use
467
     * @return array
468
     */
469
    protected function getItemsByCompositeExpression(CompositeExpression $expression = null, QueryBuilder $queryBuilder = null) : array
470
    {
471
        if (! $queryBuilder instanceof QueryBuilder) {
472
            $queryBuilder = $this->getQueryBuilder();
473
        }
474
475
        $queryBuilder->select('*')->from($this->table);
476
        if (isset($expression)) {
477
            $queryBuilder->where($expression);
478
        }
479
480
        $indexQueueItemRecords = $queryBuilder->execute()->fetchAll();
481
        return $this->getIndexQueueItemObjectsFromRecords($indexQueueItemRecords);
482
    }
483
484
    /**
485
     * Returns all items in the queue.
486
     *
487
     * @return Item[] all Items from Queue without restrictions
488
     */
489
    public function findAll() : array
490
    {
491
        $queryBuilder = $this->getQueryBuilder();
492
        $allRecords = $queryBuilder
493
            ->select('*')
494
            ->from($this->table)
495
            ->execute()->fetchAll();
496
        return $this->getIndexQueueItemObjectsFromRecords($allRecords);
497
    }
498
499
    /**
500
     * Gets $limit number of items to index for a particular $site.
501
     *
502
     * @param Site $site TYPO3 site
503
     * @param int $limit Number of items to get from the queue
504
     * @return Item[] Items to index to the given solr server
505
     */
506
    public function findItemsToIndex(Site $site, int $limit = 50) : array
507
    {
508
        $queryBuilder = $this->getQueryBuilder();
509
        // determine which items to index with this run
510
        $indexQueueItemRecords = $queryBuilder
511
            ->select('*')
512
            ->from($this->table)
513
            ->andWhere(
514
                $queryBuilder->expr()->eq('root', $site->getRootPageId()),
515
                $queryBuilder->expr()->gt('changed', 'indexed'),
516
                $queryBuilder->expr()->lte('changed', time()),
517
                $queryBuilder->expr()->eq('errors', $queryBuilder->createNamedParameter(''))
518
            )
519
            ->orderBy('indexing_priority', 'DESC')
520
            ->addOrderBy('changed', 'DESC')
521
            ->addOrderBy('uid', 'DESC')
522
            ->setMaxResults($limit)
523
            ->execute()->fetchAll();
524
525
        return $this->getIndexQueueItemObjectsFromRecords($indexQueueItemRecords);
526
    }
527
528
    /**
529
     * Creates an array of ApacheSolrForTypo3\Solr\IndexQueue\Item objects from an array of
530
     * index queue records.
531
     *
532
     * @param array $indexQueueItemRecords Array of plain index queue records
533
     * @return array Array of ApacheSolrForTypo3\Solr\IndexQueue\Item objects
534
     */
535
    protected function getIndexQueueItemObjectsFromRecords(array $indexQueueItemRecords) : array
536
    {
537
        $tableRecords = $this->getAllQueueItemRecordsByUidsGroupedByTable($indexQueueItemRecords);
538
        return $this->getQueueItemObjectsByRecords($indexQueueItemRecords, $tableRecords);
539
    }
540
541
    /**
542
     * Returns the records for suitable item type.
543
     *
544
     * @param array $indexQueueItemRecords
545
     * @return array
546
     */
547
    protected function getAllQueueItemRecordsByUidsGroupedByTable(array $indexQueueItemRecords) : array
548
    {
549
        $tableUids = [];
550
        $tableRecords = [];
551
        // grouping records by table
552
        foreach ($indexQueueItemRecords as $indexQueueItemRecord) {
553
            $tableUids[$indexQueueItemRecord['item_type']][] = $indexQueueItemRecord['item_uid'];
554
        }
555
556
        // fetching records by table, saves us a lot of single queries
557
        foreach ($tableUids as $table => $uids) {
558
            $uidList = implode(',', $uids);
559
560
            $queryBuilderForRecordTable = $this->getQueryBuilder();
561
            $queryBuilderForRecordTable->getRestrictions()->removeAll();
562
            $resultsFromRecordTable = $queryBuilderForRecordTable
563
                ->select('*')
564
                ->from($table)
565
                ->where($queryBuilderForRecordTable->expr()->in('uid', $uidList))
566
                ->execute();
567
            $records = [];
568
            while ($record = $resultsFromRecordTable->fetch()) {
569
                $records[$record['uid']] = $record;
570
            }
571
572
            $tableRecords[$table] = $records;
573
            $this->hookPostProcessFetchRecordsForIndexQueueItem($table, $uids, $tableRecords);
574
        }
575
576
        return $tableRecords;
577
    }
578
579
    /**
580
     * Calls defined in postProcessFetchRecordsForIndexQueueItem hook method.
581
     *
582
     * @param string $table
583
     * @param array $uids
584
     * @param array $tableRecords
585
     *
586
     * @return void
587
     */
588
    protected function hookPostProcessFetchRecordsForIndexQueueItem(string $table, array $uids, array &$tableRecords)
589
    {
590
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['postProcessFetchRecordsForIndexQueueItem'])) {
591
            return;
592
        }
593
        $params = ['table' => $table, 'uids' => $uids, 'tableRecords' => &$tableRecords];
594
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['postProcessFetchRecordsForIndexQueueItem'] as $reference) {
595
            GeneralUtility::callUserFunction($reference, $params, $this);
596
        }
597
    }
598
599
    /**
600
     * Instantiates a list of Item objects from database records.
601
     *
602
     * @param array $indexQueueItemRecords records from database
603
     * @param array $tableRecords
604
     * @return array
605
     */
606
    protected function getQueueItemObjectsByRecords(array $indexQueueItemRecords, array $tableRecords) : array
607
    {
608
        $indexQueueItems = [];
609
        foreach ($indexQueueItemRecords as $indexQueueItemRecord) {
610
            if (isset($tableRecords[$indexQueueItemRecord['item_type']][$indexQueueItemRecord['item_uid']])) {
611
                $indexQueueItems[] = GeneralUtility::makeInstance(
612
                    Item::class,
613
                    $indexQueueItemRecord,
614
                    $tableRecords[$indexQueueItemRecord['item_type']][$indexQueueItemRecord['item_uid']]
615
                );
616
            } else {
617
                $this->logger->log(
618
                    SolrLogManager::ERROR,
619
                    'Record missing for Index Queue item. Item removed.',
620
                    [
621
                        $indexQueueItemRecord
622
                    ]
623
                );
624
                $this->deleteItem($indexQueueItemRecord['item_type'],
625
                    $indexQueueItemRecord['item_uid']);
626
            }
627
        }
628
629
        return $indexQueueItems;
630
    }
631
632
    /**
633
     * Marks an item as failed and causes the indexer to skip the item in the
634
     * next run.
635
     *
636
     * @param int|Item $item Either the item's Index Queue uid or the complete item
637
     * @param string $errorMessage Error message
638
     * @return int affected rows
639
     */
640
    public function markItemAsFailed($item, string $errorMessage = ''): int
641
    {
642
        if ($item instanceof Item) {
643
            $itemUid = $item->getIndexQueueUid();
644
        } else {
645
            $itemUid = (int)$item;
646
        }
647
648
        if (empty($errorMessage)) {
649
            // simply set to "TRUE"
650
            $errorMessage = '1';
651
        }
652
653
        $queryBuilder = $this->getQueryBuilder();
654
        return (int)$queryBuilder
655
            ->update($this->table)
656
            ->set('errors', $errorMessage)
657
            ->where($queryBuilder->expr()->eq('uid', $itemUid))
658
            ->execute();
659
    }
660
661
    /**
662
     * Sets the timestamp of when an item last has been indexed.
663
     *
664
     * @param Item $item
665
     * @return int affected rows
666
     */
667
    public function updateIndexTimeByItem(Item $item) : int
668
    {
669
        $queryBuilder = $this->getQueryBuilder();
670
        return (int)$queryBuilder
671
            ->update($this->table)
672
            ->set('indexed', time())
673
            ->where($queryBuilder->expr()->eq('uid', $item->getIndexQueueUid()))
674
            ->execute();
675
    }
676
}
677