Passed
Push — master ( 30aafa...437b56 )
by Timo
12:12
created

Indexer::getTranslationOverlaysForPage()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 28
rs 9.3554
c 0
b 0
f 0
ccs 15
cts 15
cp 1
cc 5
nc 2
nop 2
crap 5
1
<?php
2
namespace ApacheSolrForTypo3\Solr\IndexQueue;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2009-2015 Ingo Renner <[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 3 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\ConnectionManager;
28
use ApacheSolrForTypo3\Solr\Domain\Search\ApacheSolrDocument\Builder;
29
use ApacheSolrForTypo3\Solr\FieldProcessor\Service;
30
use ApacheSolrForTypo3\Solr\NoSolrConnectionFoundException;
31
use ApacheSolrForTypo3\Solr\Domain\Site\Site;
32
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
33
use ApacheSolrForTypo3\Solr\System\Records\Pages\PagesRepository;
34
use ApacheSolrForTypo3\Solr\System\Solr\Document\Document;
35
use ApacheSolrForTypo3\Solr\System\Solr\ResponseAdapter;
36
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
37
use ApacheSolrForTypo3\Solr\Util;
38
use Solarium\Exception\HttpException;
39
use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
40
use TYPO3\CMS\Core\Context\Context;
41
use TYPO3\CMS\Core\Utility\GeneralUtility;
42
use TYPO3\CMS\Core\Utility\RootlineUtility;
43
use TYPO3\CMS\Frontend\Page\PageRepository;
44
45
/**
46
 * A general purpose indexer to be used for indexing of any kind of regular
47
 * records like tt_news, tt_address, and so on.
48
 * Specialized indexers can extend this class to handle advanced stuff like
49
 * category resolution in tt_news or file indexing.
50
 *
51
 * @author Ingo Renner <[email protected]>
52
 */
53
class Indexer extends AbstractIndexer
54
{
55
56
    # TODO change to singular $document instead of plural $documents
57
58
    /**
59
     * A Solr service instance to interact with the Solr server
60
     *
61
     * @var SolrConnection
62
     */
63
    protected $solr;
64
65
    /**
66
     * @var ConnectionManager
67
     */
68
    protected $connectionManager;
69
70
    /**
71
     * Holds options for a specific indexer
72
     *
73
     * @var array
74
     */
75
    protected $options = [];
76
77
    /**
78
     * To log or not to log... #Shakespeare
79
     *
80
     * @var bool
81
     */
82
    protected $loggingEnabled = false;
83
84
    /**
85
     * @var SolrLogManager
86
     */
87
    protected $logger = null;
88
89
    /**
90
     * @var PagesRepository
91
     */
92
    protected $pagesRepository;
93
94
    /**
95
     * @var Builder
96
     */
97
    protected $documentBuilder;
98
99
    /**
100
     * Constructor
101
     *
102
     * @param array $options array of indexer options
103
     * @param PagesRepository|null $pagesRepository
104
     * @param Builder|null $documentBuilder
105 36
     * @param SolrLogManager|null $logger
106
     * @param ConnectionManager|null $connectionManager
107 36
     */
108 36
    public function __construct(array $options = [], PagesRepository $pagesRepository = null, Builder $documentBuilder = null, SolrLogManager $logger = null, ConnectionManager $connectionManager = null)
109 36
    {
110 36
        $this->options = $options;
111 36
        $this->pagesRepository = $pagesRepository ?? GeneralUtility::makeInstance(PagesRepository::class);
112 36
        $this->documentBuilder = $documentBuilder ?? GeneralUtility::makeInstance(Builder::class);
113
        $this->logger = $logger ?? GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
114
        $this->connectionManager = $connectionManager ?? GeneralUtility::makeInstance(ConnectionManager::class);
115
    }
116
117
    /**
118
     * Indexes an item from the indexing queue.
119
     *
120 20
     * @param Item $item An index queue item
121
     * @return bool returns true when indexed, false when not
122 20
     */
123
    public function index(Item $item)
124 20
    {
125 20
        $indexed = true;
126
127 20
        $this->type = $item->getType();
128 20
        $this->setLogging($item);
129 20
130
        $solrConnections = $this->getSolrConnectionsByItem($item);
131 20
        foreach ($solrConnections as $systemLanguageUid => $solrConnection) {
132
            $this->solr = $solrConnection;
133
134
            if (!$this->indexItem($item, $systemLanguageUid)) {
135
                /*
136
                 * A single language voting for "not indexed" should make the whole
137
                 * item count as being not indexed, even if all other languages are
138
                 * indexed.
139
                 * If there is no translation for a single language, this item counts
140 20
                 * as TRUE since it's not an error which that should make the item
141
                 * being reindexed during another index run.
142
                 */
143
                $indexed = false;
144 20
            }
145
        }
146
147
        return $indexed;
148
    }
149
150
    /**
151
     * Creates a single Solr Document for an item in a specific language.
152
     *
153
     * @param Item $item An index queue item to index.
154 20
     * @param int $language The language to use.
155
     * @return bool TRUE if item was indexed successfully, FALSE on failure
156 20
     */
157 20
    protected function indexItem(Item $item, $language = 0)
158
    {
159 20
        $itemIndexed = false;
160 20
        $documents = [];
161
162
        $itemDocument = $this->itemToDocument($item, $language);
163
        if (is_null($itemDocument)) {
164
            /*
165
             * If there is no itemDocument, this means there was no translation
166
             * for this record. This should not stop the current item to count as
167 1
             * being valid because not-indexing not-translated items is perfectly
168
             * fine.
169
             */
170 20
            return true;
171 20
        }
172 20
173 20
        $documents[] = $itemDocument;
174
        $documents = array_merge($documents, $this->getAdditionalDocuments($item, $language, $itemDocument));
175 20
        $documents = $this->processDocuments($item, $documents);
176 20
        $documents = $this->preAddModifyDocuments($item, $language, $documents);
177 20
178
        try {
179
            $response = $this->solr->getWriteService()->addDocuments($documents);
180 20
            if ($response->getHttpStatus() == 200) {
181
                $itemIndexed = true;
182 20
            }
183
        } catch (HttpException $e) {
184
            $response = new ResponseAdapter($e->getBody(), $httpStatus = 500, $e->getStatusMessage());
185
        }
186
187
        $this->log($item, $documents, $response);
188
189
        return $itemIndexed;
190
    }
191
192
    /**
193
     * Gets the full item record.
194
     *
195
     * This general record indexer simply gets the record from the item. Other
196 20
     * more specialized indexers may provide more data for their specific item
197
     * types.
198 20
     *
199
     * @param Item $item The item to be indexed
200 20
     * @param int $language Language Id (sys_language.uid)
201 20
     * @return array|NULL The full record with fields of data to be used for indexing or NULL to prevent an item from being indexed
202
     */
203
    protected function getFullItemRecord(Item $item, $language = 0)
204
    {
205
        Util::initializeTsfe($item->getRootPageUid(), $language);
206
207
        $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
208 20
209 20
        $systemLanguageContentOverlay = $languageAspect->getLegacyOverlayType();
210
        $itemRecord = $this->getItemRecordOverlayed($item, $language, $systemLanguageContentOverlay);
211
212
        /*
213
         * Skip disabled records. This happens if the default language record
214
         * is hidden but a certain translation isn't. Then the default language
215
         * document appears here but must not be indexed.
216
         */
217
        if (!empty($GLOBALS['TCA'][$item->getType()]['ctrl']['enablecolumns']['disabled'])
218
            && $itemRecord[$GLOBALS['TCA'][$item->getType()]['ctrl']['enablecolumns']['disabled']]
219
        ) {
220
            $itemRecord = null;
221
        }
222
223
        /*
224 20
         * Skip translation mismatching records. Sometimes the requested language
225 20
         * doesn't fit the returned language. This might happen with content fallback
226 19
         * and is perfectly fine in general.
227
         * But if the requested language doesn't match the returned language and
228
         * the given record has no translation parent, the indexqueue_item most
229 20
         * probably pointed to a non-translated language record that is dedicated
230 20
         * to a very specific language. Now we have to avoid indexing this record
231 20
         * into all language cores.
232 20
         */
233 20
        $translationOriginalPointerField = 'l10n_parent';
234 20
        if (!empty($GLOBALS['TCA'][$item->getType()]['ctrl']['transOrigPointerField'])) {
235
            $translationOriginalPointerField = $GLOBALS['TCA'][$item->getType()]['ctrl']['transOrigPointerField'];
236 1
        }
237
238
        $languageField = $GLOBALS['TCA'][$item->getType()]['ctrl']['languageField'];
239 20
        if ($itemRecord[$translationOriginalPointerField] == 0
240 20
            && $systemLanguageContentOverlay != 1
241
            && !empty($languageField)
242
            && $itemRecord[$languageField] != $language
243 20
            && $itemRecord[$languageField] != '-1'
244
        ) {
245
            $itemRecord = null;
246
        }
247
248
        if (!is_null($itemRecord)) {
249
            $itemRecord['__solr_index_language'] = $language;
250
        }
251
252
        return $itemRecord;
253
    }
254 20
255
    /**
256 20
     * Returns the overlayed item record.
257
     *
258 20
     * @param Item $item
259 6
     * @param int $language
260 6
     * @param string|null $systemLanguageContentOverlay
261 6
     * @return array|mixed|null
262
     */
263
    protected function getItemRecordOverlayed(Item $item, $language, $systemLanguageContentOverlay)
264 20
    {
265
        $itemRecord = $item->getRecord();
266
267
        if ($language > 0) {
268 20
            $page = GeneralUtility::makeInstance(PageRepository::class);
269
            $page->init(false);
270
            $itemRecord = $page->getRecordOverlay($item->getType(), $itemRecord, $language, $systemLanguageContentOverlay);
271
        }
272
273
        if (!$itemRecord) {
274
            $itemRecord = null;
275
        }
276
277
        return $itemRecord;
278
    }
279 20
280
    /**
281 20
     * Gets the configuration how to process an item's fields for indexing.
282 20
     *
283 20
     * @param Item $item An index queue item
284 1
     * @param int $language Language ID
285 1
     * @throws \RuntimeException
286
     * @return array Configuration array from TypoScript
287
     */
288
    protected function getItemTypeConfiguration(Item $item, $language = 0)
289
    {
290
        $indexConfigurationName = $item->getIndexingConfigurationName();
291 20
        $fields = $this->getFieldConfigurationFromItemRecordPage($item, $language, $indexConfigurationName);
292
        if (!$this->isRootPageIdPartOfRootLine($item) || count($fields) === 0) {
293
            $fields = $this->getFieldConfigurationFromItemRootPage($item, $language, $indexConfigurationName);
294
            if (count($fields) === 0) {
295
                throw new \RuntimeException('The item indexing configuration "' . $item->getIndexingConfigurationName() .
296
                    '" on root page uid ' . $item->getRootPageUid() . ' could not be found!', 1455530112);
297
            }
298
        }
299
300
        return $fields;
301
    }
302 20
303
    /**
304
     * The method retrieves the field configuration of the items record page id (pid).
305 20
     *
306 19
     * @param Item $item
307 1
     * @param integer $language
308 1
     * @param string $indexConfigurationName
309
     * @return array
310
     */
311
    protected function getFieldConfigurationFromItemRecordPage(Item $item, $language, $indexConfigurationName)
312
    {
313
        try {
314
            $solrConfiguration = Util::getSolrConfigurationFromPageId($item->getRecordPageId(), true, $language);
315
            return $solrConfiguration->getIndexQueueFieldsConfigurationByConfigurationName($indexConfigurationName, []);
316
        } catch (\Exception $e) {
317
            return [];
318
        }
319
    }
320 1
321
    /**
322 1
     * The method returns the field configuration of the items root page id (uid of the related root page).
323 1
     *
324
     * @param Item $item
325
     * @param integer $language
326
     * @param string $indexConfigurationName
327 1
     * @return array
328
     */
329
    protected function getFieldConfigurationFromItemRootPage(Item $item, $language, $indexConfigurationName)
330
    {
331
        $solrConfiguration = Util::getSolrConfigurationFromPageId($item->getRootPageUid(), true, $language);
332
        if (empty($solrConfiguration->getIndexQueueAdditionalPageIdsByConfigurationName($indexConfigurationName))) {
333
            return [];
334
        }
335
336
        return $solrConfiguration->getIndexQueueFieldsConfigurationByConfigurationName($indexConfigurationName, []);
337
    }
338 20
339
    /**
340 20
     * In case of additionalStoragePid config recordPageId can be outsite of siteroot.
341
     * In that case we should not read TS config of foreign siteroot.
342 20
     *
343 20
     * @return bool
344 20
     */
345 20
    protected function isRootPageIdPartOfRootLine(Item $item)
346 20
    {
347
        $rootPageId = $item->getRootPageUid();
348
        $buildRootlineWithPid = $item->getRecordPageId();
349 20
        if ($item->getType() === 'pages') {
350
            $buildRootlineWithPid = $item->getRecordUid();
351
        }
352
        $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $buildRootlineWithPid);
353
        $rootline = $rootlineUtility->get();
354
355
        $pageInRootline = array_filter($rootline, function($page) use ($rootPageId) {
356
            return (int)$page['uid'] === $rootPageId;
357
        });
358
        return !empty($pageInRootline);
359 20
    }
360
361 20
    /**
362 20
     * Converts an item array (record) to a Solr document by mapping the
363 20
     * record's fields onto Solr document fields as configured in TypoScript.
364 20
     *
365
     * @param Item $item An index queue item
366
     * @param int $language Language Id
367
     * @return Document The Solr document converted from the record
368
     */
369
    protected function itemToDocument(Item $item, $language = 0)
370
    {
371
        $document = null;
372
373 20
        $itemRecord = $this->getFullItemRecord($item, $language);
374
        if (!is_null($itemRecord)) {
375 20
            $itemIndexingConfiguration = $this->getItemTypeConfiguration($item, $language);
376 20
            $document = $this->getBaseDocument($item, $itemRecord);
377
            $document = $this->addDocumentFieldsFromTyposcript($document, $itemIndexingConfiguration, $itemRecord);
378
        }
379
380 20
        return $document;
381 1
    }
382
383 1
    /**
384
     * Creates a Solr document with the basic / core fields set already.
385 1
     *
386
     * @param Item $item The item to index
387
     * @param array $itemRecord The record to use to build the base document
388
     * @return Document A basic Solr document
389 20
     */
390
    protected function getBaseDocument(Item $item, array $itemRecord)
391
    {
392
        $type = $item->getType();
393
        $rootPageUid = $item->getRootPageUid();
394
        $accessRootLine = $this->getAccessRootline($item);
395
        return $this->documentBuilder->fromRecord($itemRecord, $type, $rootPageUid, $accessRootLine);
396
    }
397
398
    /**
399
     * Generates an Access Rootline for an item.
400 20
     *
401
     * @param Item $item Index Queue item to index.
402
     * @return string The Access Rootline for the item
403 20
     */
404 20
    protected function getAccessRootline(Item $item)
405
    {
406
        $accessRestriction = '0';
407 20
        $itemRecord = $item->getRecord();
408 20
409 20
        // TODO support access restrictions set on storage page
410
411
        if (isset($GLOBALS['TCA'][$item->getType()]['ctrl']['enablecolumns']['fe_group'])) {
412 20
            $accessRestriction = $itemRecord[$GLOBALS['TCA'][$item->getType()]['ctrl']['enablecolumns']['fe_group']];
413
414
            if (empty($accessRestriction)) {
415
                // public
416
                $accessRestriction = '0';
417
            }
418
        }
419
420
        return 'r:' . $accessRestriction;
421
    }
422
423
    /**
424 24
     * Sends the documents to the field processing service which takes care of
425
     * manipulating fields as defined in the field's configuration.
426 24
     *
427
     * @param Item $item An index queue item
428 24
     * @param array $documents An array of Apache_Solr_Document objects to manipulate.
429 4
     * @return Document[] array Array of manipulated Document objects.
430 4
     */
431 2
    protected function processDocuments(Item $item, array $documents)
432
    {
433 2
        // needs to respect the TS settings for the page the item is on, conditions may apply
434 2
        $solrConfiguration = Util::getSolrConfigurationFromPageId($item->getRootPageUid());
435 1
        $fieldProcessingInstructions = $solrConfiguration->getIndexFieldProcessingInstructionsConfiguration();
436
437 1
        // same as in the FE indexer
438 1
        if (is_array($fieldProcessingInstructions)) {
0 ignored issues
show
introduced by
The condition is_array($fieldProcessingInstructions) is always true.
Loading history...
439 1
            $service = GeneralUtility::makeInstance(Service::class);
440
            $service->processDocuments($documents, $fieldProcessingInstructions);
441
        }
442 1
443 1
        return $documents;
444 2
    }
445
446
    /**
447
     * Allows third party extensions to provide additional documents which
448
     * should be indexed for the current item.
449 21
     *
450
     * @param Item $item The item currently being indexed.
451
     * @param int $language The language uid currently being indexed.
452
     * @param Document $itemDocument The document representing the item for the given language.
453
     * @return Document[] array An array of additional Document objects to index.
454
     */
455
    protected function getAdditionalDocuments(Item $item, $language, Document $itemDocument)
456
    {
457
        $documents = [];
458
459
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['IndexQueueIndexer']['indexItemAddDocuments'])) {
460
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['IndexQueueIndexer']['indexItemAddDocuments'] as $classReference) {
461 20
                if (!class_exists($classReference)) {
462
                    throw new \InvalidArgumentException('Class does not exits' . $classReference, 1490363487);
463 20
                }
464
                $additionalIndexer = GeneralUtility::makeInstance($classReference);
465
                if ($additionalIndexer instanceof AdditionalIndexQueueItemIndexer) {
466
                    $additionalDocuments = $additionalIndexer->getAdditionalItemDocuments($item, $language, $itemDocument);
467
468
                    if (is_array($additionalDocuments)) {
469
                        $documents = array_merge($documents,
470
                            $additionalDocuments);
471
                    }
472
                } else {
473
                    throw new \UnexpectedValueException(
474
                        get_class($additionalIndexer) . ' must implement interface ' . AdditionalIndexQueueItemIndexer::class,
475
                        1326284551
476
                    );
477
                }
478
            }
479
        }
480
        return $documents;
481 20
    }
482
483
    /**
484
     * Provides a hook to manipulate documents right before they get added to
485
     * the Solr index.
486
     *
487
     * @param Item $item The item currently being indexed.
488
     * @param int $language The language uid of the documents
489
     * @param array $documents An array of documents to be indexed
490
     * @return array An array of modified documents
491
     */
492
    protected function preAddModifyDocuments(Item $item, $language, array $documents)
493
    {
494
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['IndexQueueIndexer']['preAddModifyDocuments'])) {
495 22
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['IndexQueueIndexer']['preAddModifyDocuments'] as $classReference) {
496
                $documentsModifier = GeneralUtility::makeInstance($classReference);
497 22
498
                if ($documentsModifier instanceof PageIndexerDocumentsModifier) {
499 22
                    $documents = $documentsModifier->modifyDocuments($item, $language, $documents);
500 22
                } else {
501 2
                    throw new \RuntimeException(
502
                        'The class "' . get_class($documentsModifier)
503
                        . '" registered as document modifier in hook
504
							preAddModifyDocuments must implement interface
505 22
							ApacheSolrForTypo3\Solr\IndexQueue\PageIndexerDocumentsModifier',
506
                        1309522677
507 22
                    );
508 22
                }
509 22
            }
510 22
        }
511
512
        return $documents;
513 22
    }
514 22
515
    // Initialization
516 22
517 22
    /**
518
     * Gets the Solr connections applicable for an item.
519 22
     *
520 21
     * The connections include the default connection and connections to be used
521
     * for translations of an item.
522
     *
523 22
     * @param Item $item An index queue item
524 7
     * @return array An array of ApacheSolrForTypo3\Solr\System\Solr\SolrConnection connections, the array's keys are the sys_language_uid of the language of the connection
525
     */
526 22
    protected function getSolrConnectionsByItem(Item $item)
527
    {
528
        $solrConnections = [];
529
530
        $pageId = $item->getRootPageUid();
531
        if ($item->getType() === 'pages') {
532
            $pageId = $item->getRecordUid();
533
        }
534
535
        // Solr configurations possible for this item
536
        $site = $item->getSite();
537
        $solrConfigurationsBySite = $site->getAllSolrConnectionConfigurations();
538 22
        $siteLanguages = [];
539
        foreach ($solrConfigurationsBySite as $solrConfiguration) {
540 22
            $siteLanguages[] = $solrConfiguration['language'];
541
        }
542 22
543 7
        $defaultLanguageUid = $this->getDefaultLanguageUid($item, $site->getRootPage(), $siteLanguages);
544 7
        $translationOverlays = $this->getTranslationOverlaysWithConfiguredSite((int)$pageId, $site, (array)$siteLanguages);
545
546
        $defaultConnection = $this->connectionManager->getConnectionByPageId($pageId, 0, $item->getMountPointIdentifier());
547
        $translationConnections = $this->getConnectionsForIndexableLanguages($translationOverlays);
548 22
549
        if ($defaultLanguageUid == 0) {
550
            $solrConnections[0] = $defaultConnection;
551
        }
552
553
        foreach ($translationConnections as $systemLanguageUid => $solrConnection) {
554
            $solrConnections[$systemLanguageUid] = $solrConnection;
555
        }
556
        return $solrConnections;
557
    }
558
559 22
    /**
560
     * @param int $pageId
561 22
     * @param Site $site
562 22
     * @param array $siteLanguages
563 1
     * @return array
564 1
     */
565 21
    protected function getTranslationOverlaysWithConfiguredSite(int $pageId, Site $site, array $siteLanguages): array
566
    {
567
        $translationOverlays = $this->pagesRepository->findTranslationOverlaysByPageId($pageId);
568
        $translatedLanguages = [];
569
        foreach ($translationOverlays as $key => $translationOverlay) {
570 22
            if (!in_array($translationOverlay['sys_language_uid'], $siteLanguages)) {
571
                unset($translationOverlays[$key]);
572
            } else {
573
                $translatedLanguages[] = (int)$translationOverlay['sys_language_uid'];
574
            }
575
        }
576
577
        if (count($translationOverlays) + 1 !== count($siteLanguages)) {
578
            // not all Languages are translated
579
            // add Language Fallback
580
            foreach ($siteLanguages as $languageId) {
581
                if ($languageId !== 0 && !in_array((int)$languageId, $translatedLanguages, true)) {
582
                    $fallbackLanguageIds = $site->getFallbackOrder((int)$languageId);
583
                    foreach ($fallbackLanguageIds as $fallbackLanguageId) {
584
                        if ($fallbackLanguageId === 0 || in_array((int)$fallbackLanguageId, $translatedLanguages, true)) {
585
                            $translationOverlay = [
586
                                'pid' => $pageId,
587 22
                                'sys_language_uid' => $languageId,
588
                                'l10n_parent' => $pageId
589 22
                            ];
590 22
                            $translationOverlays[] = $translationOverlay;
591
                            continue 2;
592 22
                        }
593 22
                    }
594 22
                }
595 22
            }
596
        }
597 22
        return $translationOverlays;
598 6
    }
599
600
601 16
    /**
602 16
     * @param Item $item An index queue item
603 15
     * @param array $rootPage
604 15
     * @param array $siteLanguages
605
     *
606 1
     * @return int
607 1
     * @throws \RuntimeException
608 1
     */
609 1
    private function getDefaultLanguageUid(Item $item, array $rootPage, array $siteLanguages)
610
    {
611
        $defaultLanguageUid = 0;
612
        if (($rootPage['l18n_cfg'] & 1) == 1 && count($siteLanguages) > 1) {
613
            unset($siteLanguages[array_search('0', $siteLanguages)]);
614 22
            $defaultLanguageUid = $siteLanguages[min(array_keys($siteLanguages))];
615
        } elseif (($rootPage['l18n_cfg'] & 1) == 1 && count($siteLanguages) == 1) {
616
            $message = 'Root page ' . (int)$item->getRootPageUid() . ' is set to hide default translation, but no other language is configured!';
617
            throw new \RuntimeException($message);
618
        }
619
620
        return $defaultLanguageUid;
621
    }
622 15
623
    /**
624 15
     * Checks for which languages connections have been configured and returns
625
     * these connections.
626
     *
627
     * @param array $translationOverlays An array of translation overlays to check for configured connections.
628
     * @return array An array of ApacheSolrForTypo3\Solr\System\Solr\SolrConnection connections.
629
     */
630
    protected function getConnectionsForIndexableLanguages(array $translationOverlays)
631
    {
632
        $connections = [];
633
634 22
        foreach ($translationOverlays as $translationOverlay) {
635
            $pageId = $translationOverlay['l10n_parent'];
636 22
            $languageId = $translationOverlay['sys_language_uid'];
637
638 22
            try {
639
                $connection = $this->connectionManager->getConnectionByPageId($pageId, $languageId);
640 7
                $connections[$languageId] = $connection;
641 7
            } catch (NoSolrConnectionFoundException $e) {
642
                // ignore the exception as we seek only those connections
643
                // actually available
644 7
            }
645 7
        }
646 7
647
        return $connections;
648
    }
649
650
    // Utility methods
651
652 22
    // FIXME extract log() and setLogging() to ApacheSolrForTypo3\Solr\IndexQueue\AbstractIndexer
653
    // FIXME extract an interface Tx_Solr_IndexQueue_ItemInterface
654
655
    /**
656
     * Enables logging dependent on the configuration of the item's site
657
     *
658
     * @param Item $item An item being indexed
659
     * @return    void
660
     */
661
    protected function setLogging(Item $item)
662
    {
663
        $solrConfiguration = Util::getSolrConfigurationFromPageId($item->getRootPageUid());
664
        $this->loggingEnabled = $solrConfiguration->getLoggingIndexingQueueOperationsByConfigurationNameWithFallBack(
665
            $item->getIndexingConfigurationName()
666 21
        );
667
    }
668 21
669 21
    /**
670 21
     * Logs the item and what document was created from it
671
     *
672 21
     * @param Item $item The item that is being indexed.
673
     * @param array $itemDocuments An array of Solr documents created from the item's data
674
     * @param ResponseAdapter $response The Solr response for the particular index document
675
     */
676
    protected function log(Item $item, array $itemDocuments, ResponseAdapter $response)
677
    {
678
        if (!$this->loggingEnabled) {
679
            return;
680
        }
681 20
682
        $message = 'Index Queue indexing ' . $item->getType() . ':' . $item->getRecordUid() . ' - ';
683 20
684 20
        // preparing data
685
        $documents = [];
686
        foreach ($itemDocuments as $document) {
687
            $documents[] = (array)$document;
688
        }
689
690
        $logData = ['item' => (array)$item, 'documents' => $documents, 'response' => (array)$response];
691
692
        if ($response->getHttpStatus() == 200) {
693
            $severity = SolrLogManager::NOTICE;
694
            $message .= 'Success';
695
        } else {
696
            $severity = SolrLogManager::ERROR;
697
            $message .= 'Failure';
698
699
            $logData['status'] = $response->getHttpStatus();
700
            $logData['status message'] = $response->getHttpStatusMessage();
701
        }
702
703
        $this->logger->log($severity, $message, $logData);
704
    }
705
}
706