Completed
Push — master ( d2e609...7e8018 )
by Timo
18s
created

findPageIdsOfExistingMountPagesByMountIdentifier()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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