Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 3e7fda...da8841 )
by
unknown
04:11
created

Indexer::deleteDocument()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 2
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
5
 *
6
 * This file is part of the Kitodo and TYPO3 projects.
7
 *
8
 * @license GNU General Public License version 3 or later.
9
 * For the full copyright and license information, please read the
10
 * LICENSE.txt file that was distributed with this source code.
11
 */
12
13
namespace Kitodo\Dlf\Common;
14
15
use Kitodo\Dlf\Common\Solr\Solr;
16
use Kitodo\Dlf\Domain\Repository\DocumentRepository;
17
use Kitodo\Dlf\Domain\Model\Document;
18
use Solarium\Core\Query\DocumentInterface;
19
use Solarium\QueryType\Update\Query\Query;
20
use Symfony\Component\Console\Input\InputInterface;
21
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
22
use TYPO3\CMS\Core\Database\ConnectionPool;
23
use TYPO3\CMS\Core\Messaging\FlashMessage;
24
use TYPO3\CMS\Core\Utility\GeneralUtility;
25
use TYPO3\CMS\Core\Utility\MathUtility;
26
use TYPO3\CMS\Core\Core\Environment;
27
28
/**
29
 * Indexer class for the 'dlf' extension
30
 *
31
 * @package TYPO3
32
 * @subpackage dlf
33
 *
34
 * @access public
35
 */
36
class Indexer
37
{
38
    /**
39
     * @access public
40
     * @static
41
     * @var string The extension key
42
     */
43
    public static string $extKey = 'dlf';
44
45
    /**
46
     * @access protected
47
     * @static
48
     * @var array Array of metadata fields' configuration
49
     *
50
     * @see loadIndexConf()
51
     */
52
    protected static array $fields = [
53
        'autocomplete' => [],
54
        'facets' => [],
55
        'sortables' => [],
56
        'indexed' => [],
57
        'stored' => [],
58
        'tokenized' => [],
59
        'fieldboost' => []
60
    ];
61
62
    /**
63
     * @access protected
64
     * @static
65
     * @var bool Is the index configuration loaded?
66
     *
67
     * @see $fields
68
     */
69
    protected static bool $fieldsLoaded = false;
70
71
    /**
72
     * @access protected
73
     * @static
74
     * @var array List of already processed documents
75
     */
76
    protected static array $processedDocs = [];
77
78
    /**
79
     * @access protected
80
     * @static
81
     * @var Solr Instance of Solr class
82
     */
83
    protected static Solr $solr;
84
85
    /**
86
     * Insert given document into Solr index
87
     *
88
     * @access public
89
     *
90
     * @static
91
     *
92
     * @param Document $document The document to add
93
     * @param DocumentRepository $documentRepository The document repository for search of parent
94
     *
95
     * @return bool true on success or false on failure
96
     */
97
    public static function add(Document $document, DocumentRepository $documentRepository): bool
98
    {
99
        if (in_array($document->getUid(), self::$processedDocs)) {
100
            return true;
101
        } elseif (self::solrConnect($document->getSolrcore(), $document->getPid())) {
0 ignored issues
show
Bug introduced by
It seems like $document->getPid() can also be of type null; however, parameter $pid of Kitodo\Dlf\Common\Indexer::solrConnect() 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

101
        } elseif (self::solrConnect($document->getSolrcore(), /** @scrutinizer ignore-type */ $document->getPid())) {
Loading history...
102
            $success = true;
103
            Helper::getLanguageService()->includeLLFile('EXT:dlf/Resources/Private/Language/locallang_be.xlf');
104
            // Handle multi-volume documents.
105
            $parentId = $document->getPartof();
106
            if ($parentId) {
107
                // get parent document
108
                $parent = $documentRepository->findByUid($parentId);
109
                if ($parent) {
110
                    // get XML document of parent
111
                    $doc = AbstractDocument::getInstance($parent->getLocation(), ['storagePid' => $parent->getPid()], true);
112
                    if ($doc !== null) {
113
                        $parent->setCurrentDocument($doc);
114
                        $success = self::add($parent, $documentRepository);
115
                    } else {
116
                        Helper::log('Could not load parent document with UID ' . $document->getCurrentDocument()->parentId, LOG_SEVERITY_ERROR);
117
                        return false;
118
                    }
119
                }
120
            }
121
            try {
122
                // Add document to list of processed documents.
123
                self::$processedDocs[] = $document->getUid();
124
                // Delete old Solr documents.
125
                self::deleteDocument('uid', (string) $document->getUid());
126
127
                // Index every logical unit as separate Solr document.
128
                foreach ($document->getCurrentDocument()->tableOfContents as $logicalUnit) {
129
                    if ($success) {
130
                        $success = self::processLogical($document, $logicalUnit);
131
                    } else {
132
                        break;
133
                    }
134
                }
135
                // Index full text files if available.
136
                if ($document->getCurrentDocument()->hasFulltext) {
137
                    foreach ($document->getCurrentDocument()->physicalStructure as $pageNumber => $xmlId) {
138
                        if ($success) {
139
                            $success = self::processPhysical($document, $pageNumber, $document->getCurrentDocument()->physicalStructureInfo[$xmlId]);
140
                        } else {
141
                            break;
142
                        }
143
                    }
144
                }
145
                // Commit all changes.
146
                $updateQuery = self::$solr->service->createUpdate();
147
                $updateQuery->addCommit();
148
                self::$solr->service->update($updateQuery);
149
150
                if (!(Environment::isCli())) {
151
                    if ($success) {
152
                        self::addMessage(
153
                            sprintf(Helper::getLanguageService()->getLL('flash.documentIndexed'), $document->getTitle(), $document->getUid()),
154
                            'flash.done',
155
                            FlashMessage::OK
156
                        );
157
                    } else {
158
                        self::addErrorMessage(sprintf(Helper::getLanguageService()->getLL('flash.documentNotIndexed'), $document->getTitle(), $document->getUid()));
159
                    }
160
                }
161
                return $success;
162
            } catch (\Exception $e) {
163
                self::handleException($e->getMessage());
164
                return false;
165
            }
166
        } else {
167
            if (!(Environment::isCli())) {
168
                self::addMessage(
169
                    Helper::getLanguageService()->getLL('flash.solrNoConnection'),
170
                    'flash.warning',
171
                    FlashMessage::WARNING
172
                );
173
            }
174
            Helper::log('Could not connect to Apache Solr server', LOG_SEVERITY_ERROR);
175
            return false;
176
        }
177
    }
178
179
    /**
180
     * Delete document from Solr index
181
     *
182
     * @access public
183
     *
184
     * @static
185
     *
186
     * @param InputInterface $input The input parameters
187
     *
188
     * @return bool true on success or false on failure
189
     */
190
    public static function delete(InputInterface $input, string $field, int $solrCoreUid): bool
191
    {
192
        if (self::solrConnect($solrCoreUid, $input->getOption('pid'))) {
193
            try {
194
                self::deleteDocument($field, $input->getOption('doc'));
195
                return true;
196
            } catch (\Exception $e) {
197
                if (!(Environment::isCli())) {
198
                    Helper::addMessage(
199
                        Helper::getLanguageService()->getLL('flash.solrException') . ' ' . htmlspecialchars($e->getMessage()),
200
                        Helper::getLanguageService()->getLL('flash.error'),
201
                        FlashMessage::ERROR,
202
                        true,
203
                        'core.template.flashMessages'
204
                    );
205
                }
206
                Helper::log('Apache Solr threw exception: "' . $e->getMessage() . '"', LOG_SEVERITY_ERROR);
207
                return false;
208
            }
209
        }
210
211
        Helper::log('Document not deleted from SOLR - problem with the connection to the SOLR core ' . $solrCoreUid, LOG_SEVERITY_ERROR);
212
        return false;
213
    }
214
215
    /**
216
     * Returns the dynamic index field name for the given metadata field.
217
     *
218
     * @access public
219
     *
220
     * @static
221
     *
222
     * @param string $indexName The metadata field's name in database
223
     * @param int $pid UID of the configuration page
224
     *
225
     * @return string The field's dynamic index name
226
     */
227
    public static function getIndexFieldName(string $indexName, int $pid = 0): string
228
    {
229
        // Sanitize input.
230
        $pid = max((int) $pid, 0);
231
        if (!$pid) {
232
            Helper::log('Invalid PID ' . $pid . ' for metadata configuration', LOG_SEVERITY_ERROR);
233
            return '';
234
        }
235
        // Load metadata configuration.
236
        self::loadIndexConf($pid);
237
        // Build field's suffix.
238
        $suffix = (in_array($indexName, self::$fields['tokenized']) ? 't' : 'u');
239
        $suffix .= (in_array($indexName, self::$fields['stored']) ? 's' : 'u');
240
        $suffix .= (in_array($indexName, self::$fields['indexed']) ? 'i' : 'u');
241
        $indexName .= '_' . $suffix;
242
        return $indexName;
243
    }
244
245
    /**
246
     * Load indexing configuration
247
     *
248
     * @access protected
249
     *
250
     * @static
251
     *
252
     * @param int $pid The configuration page's UID
253
     *
254
     * @return void
255
     */
256
    protected static function loadIndexConf(int $pid): void
257
    {
258
        if (!self::$fieldsLoaded) {
259
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
260
                ->getQueryBuilderForTable('tx_dlf_metadata');
261
262
            // Get the metadata indexing options.
263
            $result = $queryBuilder
264
                ->select(
265
                    'tx_dlf_metadata.index_name AS index_name',
266
                    'tx_dlf_metadata.index_tokenized AS index_tokenized',
267
                    'tx_dlf_metadata.index_stored AS index_stored',
268
                    'tx_dlf_metadata.index_indexed AS index_indexed',
269
                    'tx_dlf_metadata.is_sortable AS is_sortable',
270
                    'tx_dlf_metadata.is_facet AS is_facet',
271
                    'tx_dlf_metadata.is_listed AS is_listed',
272
                    'tx_dlf_metadata.index_autocomplete AS index_autocomplete',
273
                    'tx_dlf_metadata.index_boost AS index_boost'
274
                )
275
                ->from('tx_dlf_metadata')
276
                ->where(
277
                    $queryBuilder->expr()->eq('tx_dlf_metadata.pid', (int) $pid),
278
                    Helper::whereExpression('tx_dlf_metadata')
279
                )
280
                ->execute();
281
282
            while ($indexing = $result->fetchAssociative()) {
283
                if ($indexing['index_tokenized']) {
284
                    self::$fields['tokenized'][] = $indexing['index_name'];
285
                }
286
                if (
287
                    $indexing['index_stored']
288
                    || $indexing['is_listed']
289
                ) {
290
                    self::$fields['stored'][] = $indexing['index_name'];
291
                }
292
                if (
293
                    $indexing['index_indexed']
294
                    || $indexing['index_autocomplete']
295
                ) {
296
                    self::$fields['indexed'][] = $indexing['index_name'];
297
                }
298
                if ($indexing['is_sortable']) {
299
                    self::$fields['sortables'][] = $indexing['index_name'];
300
                }
301
                if ($indexing['is_facet']) {
302
                    self::$fields['facets'][] = $indexing['index_name'];
303
                }
304
                if ($indexing['index_autocomplete']) {
305
                    self::$fields['autocomplete'][] = $indexing['index_name'];
306
                }
307
                if ($indexing['index_boost'] > 0.0) {
308
                    self::$fields['fieldboost'][$indexing['index_name']] = floatval($indexing['index_boost']);
309
                } else {
310
                    self::$fields['fieldboost'][$indexing['index_name']] = false;
311
                }
312
            }
313
            self::$fieldsLoaded = true;
314
        }
315
    }
316
317
    /**
318
     * Processes a logical unit (and its children) for the Solr index
319
     *
320
     * @access protected
321
     *
322
     * @static
323
     *
324
     * @param Document $document The METS document
325
     * @param array $logicalUnit Array of the logical unit to process
326
     *
327
     * @return bool true on success or false on failure
328
     */
329
    protected static function processLogical(Document $document, array $logicalUnit): bool
330
    {
331
        $success = true;
332
        $doc = $document->getCurrentDocument();
333
        $doc->cPid = $document->getPid();
334
        // Get metadata for logical unit.
335
        $metadata = $doc->metadataArray[$logicalUnit['id']];
336
        if (!empty($metadata)) {
337
            $metadata['author'] = self::removeAppendsFromAuthor($metadata['author']);
338
            // set Owner if available
339
            if ($document->getOwner()) {
340
                $metadata['owner'][0] = $document->getOwner()->getIndexName();
341
            }
342
            // Create new Solr document.
343
            $updateQuery = self::$solr->service->createUpdate();
344
            $solrDoc = self::getSolrDocument($updateQuery, $document, $logicalUnit);
345
            if (MathUtility::canBeInterpretedAsInteger($logicalUnit['points'])) {
346
                $solrDoc->setField('page', $logicalUnit['points']);
0 ignored issues
show
Bug introduced by
The method setField() does not exist on Solarium\Core\Query\DocumentInterface. It seems like you code against a sub-type of Solarium\Core\Query\DocumentInterface such as Solarium\Plugin\MinimumScoreFilter\Document or Solarium\QueryType\Update\Query\Document. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

346
                $solrDoc->/** @scrutinizer ignore-call */ 
347
                          setField('page', $logicalUnit['points']);
Loading history...
347
            }
348
            if ($logicalUnit['id'] == $doc->toplevelId) {
349
                $solrDoc->setField('thumbnail', $doc->thumbnail);
350
            } elseif (!empty($logicalUnit['thumbnailId'])) {
351
                $solrDoc->setField('thumbnail', $doc->getFileLocation($logicalUnit['thumbnailId']));
352
            }
353
            // There can be only one toplevel unit per UID, independently of backend configuration
354
            $solrDoc->setField('toplevel', $logicalUnit['id'] == $doc->toplevelId ? true : false);
355
            $solrDoc->setField('title', $metadata['title'][0], self::$fields['fieldboost']['title']);
356
            $solrDoc->setField('volume', $metadata['volume'][0], self::$fields['fieldboost']['volume']);
357
            // verify date formatting
358
            if(strtotime($metadata['date'][0])) {
359
                $solrDoc->setField('date', self::getFormattedDate($metadata['date'][0]));
360
            }
361
            $solrDoc->setField('record_id', $metadata['record_id'][0]);
362
            $solrDoc->setField('purl', $metadata['purl'][0]);
363
            $solrDoc->setField('location', $document->getLocation());
364
            $solrDoc->setField('urn', $metadata['urn']);
365
            $solrDoc->setField('license', $metadata['license']);
366
            $solrDoc->setField('terms', $metadata['terms']);
367
            $solrDoc->setField('restrictions', $metadata['restrictions']);
368
            $coordinates = json_decode($metadata['coordinates'][0]);
369
            if (is_object($coordinates)) {
370
                $solrDoc->setField('geom', json_encode($coordinates->features[0]));
371
            }
372
            $autocomplete = self::processMetadata($document, $metadata, $solrDoc);
373
            // Add autocomplete values to index.
374
            if (!empty($autocomplete)) {
375
                $solrDoc->setField('autocomplete', $autocomplete);
376
            }
377
            // Add collection information to logical sub-elements if applicable.
378
            if (
379
                in_array('collection', self::$fields['facets'])
380
                && empty($metadata['collection'])
381
                && !empty($doc->metadataArray[$doc->toplevelId]['collection'])
382
            ) {
383
                $solrDoc->setField('collection_faceting', $doc->metadataArray[$doc->toplevelId]['collection']);
384
            }
385
            try {
386
                $updateQuery->addDocument($solrDoc);
387
                self::$solr->service->update($updateQuery);
388
            } catch (\Exception $e) {
389
                self::handleException($e->getMessage());
390
                return false;
391
            }
392
        }
393
        // Check for child elements...
394
        if (!empty($logicalUnit['children'])) {
395
            foreach ($logicalUnit['children'] as $child) {
396
                if ($success) {
397
                    // ...and process them, too.
398
                    $success = self::processLogical($document, $child);
399
                } else {
400
                    break;
401
                }
402
            }
403
        }
404
        return $success;
405
    }
406
407
    /**
408
     * Processes a physical unit for the Solr index
409
     *
410
     * @access protected
411
     *
412
     * @static
413
     *
414
     * @param Document $document The METS document
415
     * @param int $page The page number
416
     * @param array $physicalUnit Array of the physical unit to process
417
     *
418
     * @return bool true on success or false on failure
419
     */
420
    protected static function processPhysical(Document $document, int $page, array $physicalUnit): bool
421
    {
422
        $doc = $document->getCurrentDocument();
423
        $doc->cPid = $document->getPid();
424
        if ($doc->hasFulltext && $fullText = $doc->getFullText($physicalUnit['id'])) {
425
            // Read extension configuration.
426
            $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get(self::$extKey);
427
            // Create new Solr document.
428
            $updateQuery = self::$solr->service->createUpdate();
429
            $solrDoc = self::getSolrDocument($updateQuery, $document, $physicalUnit, $fullText);
430
            $solrDoc->setField('page', $page);
431
            $fileGrpsThumb = GeneralUtility::trimExplode(',', $extConf['fileGrpThumbs']);
432
            while ($fileGrpThumb = array_shift($fileGrpsThumb)) {
433
                if (!empty($physicalUnit['files'][$fileGrpThumb])) {
434
                    $solrDoc->setField('thumbnail', $doc->getFileLocation($physicalUnit['files'][$fileGrpThumb]));
435
                    break;
436
                }
437
            }
438
            $solrDoc->setField('toplevel', false);
439
            $solrDoc->setField('type', $physicalUnit['type'], self::$fields['fieldboost']['type']);
440
            $solrDoc->setField('collection', $doc->metadataArray[$doc->toplevelId]['collection']);
441
            $solrDoc->setField('location', $document->getLocation());
442
443
            $solrDoc->setField('fulltext', $fullText);
444
            if (is_array($doc->metadataArray[$doc->toplevelId])) {
445
                self::addFaceting($doc, $solrDoc);
446
            }
447
            // Add collection information to physical sub-elements if applicable.
448
            if (
449
                in_array('collection', self::$fields['facets'])
450
                && !empty($doc->metadataArray[$doc->toplevelId]['collection'])
451
            ) {
452
                $solrDoc->setField('collection_faceting', $doc->metadataArray[$doc->toplevelId]['collection']);
453
            }
454
            try {
455
                $updateQuery->addDocument($solrDoc);
456
                self::$solr->service->update($updateQuery);
457
            } catch (\Exception $e) {
458
                self::handleException($e->getMessage());
459
                return false;
460
            }
461
        }
462
        return true;
463
    }
464
465
    /**
466
     * Connects to Solr server.
467
     *
468
     * @access protected
469
     *
470
     * @static
471
     *
472
     * @param int $core UID of the Solr core
473
     * @param int $pid UID of the configuration page
474
     *
475
     * @return bool true on success or false on failure
476
     */
477
    protected static function solrConnect(int $core, int $pid = 0): bool
478
    {
479
        // Get Solr instance.
480
        $solr = Solr::getInstance($core);
481
        // Connect to Solr server.
482
        if ($solr->ready) {
483
            self::$solr = $solr;
484
            // Load indexing configuration if needed.
485
            if ($pid) {
486
                self::loadIndexConf($pid);
487
            }
488
            return true;
489
        }
490
        return false;
491
    }
492
493
    /**
494
     * Process metadata: add facets, sortable fields and create autocomplete array.
495
     *
496
     * @static
497
     *
498
     * @access private
499
     *
500
     * @param Document $document
501
     * @param array $metadata
502
     * @param DocumentInterface &$solrDoc
503
     *
504
     * @return array empty array or autocomplete values
505
     */
506
    private static function processMetadata($document, $metadata, &$solrDoc): array
507
    {
508
        $autocomplete = [];
509
        foreach ($metadata as $indexName => $data) {
510
            if (
511
                !empty($data)
512
                && substr($indexName, -8) !== '_sorting'
513
            ) {
514
                $solrDoc->setField(self::getIndexFieldName($indexName, $document->getPid()), $data, self::$fields['fieldboost'][$indexName]);
0 ignored issues
show
Bug introduced by
It seems like $document->getPid() can also be of type null; however, parameter $pid of Kitodo\Dlf\Common\Indexer::getIndexFieldName() 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

514
                $solrDoc->setField(self::getIndexFieldName($indexName, /** @scrutinizer ignore-type */ $document->getPid()), $data, self::$fields['fieldboost'][$indexName]);
Loading history...
515
                if (in_array($indexName, self::$fields['sortables'])) {
516
                    // Add sortable fields to index.
517
                    $solrDoc->setField($indexName . '_sorting', $metadata[$indexName . '_sorting'][0]);
518
                }
519
                if (in_array($indexName, self::$fields['facets'])) {
520
                    // Add facets to index.
521
                    $solrDoc->setField($indexName . '_faceting', $data);
522
                }
523
                if (in_array($indexName, self::$fields['autocomplete'])) {
524
                    $autocomplete = array_merge($autocomplete, $data);
525
                }
526
            }
527
        }
528
        return $autocomplete;
529
    }
530
531
    /**
532
     * Add faceting information to physical sub-elements if applicable.
533
     *
534
     * @static
535
     *
536
     * @access private
537
     *
538
     * @param AbstractDocument $doc
539
     * @param DocumentInterface &$solrDoc
540
     *
541
     * @return void
542
     */
543
    private static function addFaceting($doc, &$solrDoc): void
544
    {
545
        foreach ($doc->metadataArray[$doc->toplevelId] as $indexName => $data) {
546
            if (
547
                !empty($data)
548
                && substr($indexName, -8) !== '_sorting'
549
            ) {
550
551
                if (in_array($indexName, self::$fields['facets'])) {
552
                    // Remove appended "valueURI" from authors' names for indexing.
553
                    if ($indexName == 'author') {
554
                        $data = self::removeAppendsFromAuthor($data);
555
                    }
556
                    // Add facets to index.
557
                    $solrDoc->setField($indexName . '_faceting', $data);
558
                }
559
            }
560
            // Add sorting information to physical sub-elements if applicable.
561
            if (
562
                !empty($data)
563
                && substr($indexName, -8) == '_sorting'
564
            ) {
565
                $solrDoc->setField($indexName, $doc->metadataArray[$doc->toplevelId][$indexName]);
566
            }
567
        }
568
    }
569
570
    /**
571
     * Delete document from SOLR by given field and value.
572
     *
573
     * @access private
574
     *
575
     * @static
576
     *
577
     * @param string $field by which document should be removed
578
     * @param string $value of the field by which document should be removed
579
     *
580
     * @return void
581
     */
582
    private static function deleteDocument(string $field, string $value): void
583
    {
584
        $update = self::$solr->service->createUpdate();
585
        $query = "";
586
        if ($field == 'uid' || $field == 'partof') {
587
            $query = $field . ':' . $value;
588
        } else {
589
            $query = $field . ':"' . $value . '"';
590
        }
591
        $update->addDeleteQuery($query);
592
        $update->addCommit();
593
        self::$solr->service->update($update);
594
    }
595
596
    /**
597
     * Get SOLR document with set standard fields (identical for logical and physical unit)
598
     *
599
     * @access private
600
     *
601
     * @static
602
     *
603
     * @param Query $updateQuery solarium query
604
     * @param Document $document The METS document
605
     * @param array $unit Array of the logical or physical unit to process
606
     * @param string $fullText Text containing full text for indexing
607
     *
608
     * @return DocumentInterface
609
     */
610
    private static function getSolrDocument(Query $updateQuery, Document $document, array $unit, string $fullText = ''): DocumentInterface
611
    {
612
        $solrDoc = $updateQuery->createDocument();
613
        // Create unique identifier from document's UID and unit's XML ID.
614
        $solrDoc->setField('id', $document->getUid() . $unit['id']);
615
        $solrDoc->setField('uid', $document->getUid());
616
        $solrDoc->setField('pid', $document->getPid());
617
        $solrDoc->setField('partof', $document->getPartof());
618
        $solrDoc->setField('root', $document->getCurrentDocument()->rootId);
619
        $solrDoc->setField('sid', $unit['id']);
620
        $solrDoc->setField('type', $unit['type'], self::$fields['fieldboost']['type']);
621
        $solrDoc->setField('collection', $document->getCurrentDocument()->metadataArray[$document->getCurrentDocument()->toplevelId]['collection']);
622
        $solrDoc->setField('fulltext', $fullText);
623
        return $solrDoc;
624
    }
625
626
    /**
627
     * Get formatted date without alteration.
628
     * Possible formats: YYYY or YYYY-MM or YYYY-MM-DD.
629
     *
630
     * @static
631
     *
632
     * @access private
633
     *
634
     * @param string $date
635
     *
636
     * @return string formatted date YYYY or YYYY-MM or YYYY-MM-DD or empty string
637
     */
638
    private static function getFormattedDate($date): string
639
    {
640
        if (
641
            preg_match("/^[\d]{4}$/", $date)
642
            || preg_match("/^[\d]{4}-[\d]{2}$/", $date)
643
            || preg_match("/^[\d]{4}-[\d]{2}-[\d]{2}$/", $date)
644
        ) {
645
            return $date;
646
        // change date YYYYMMDD to YYYY-MM-DD
647
        } elseif (preg_match("/^[\d]{8}$/", $date)) {
648
            return date("Y-m-d", strtotime($date));
649
        // convert any datetime to proper ISO extended datetime format and timezone for SOLR
650
        } elseif (preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*$/", $date)) {
651
            return date('Y-m-d\TH:i:s\Z', strtotime($date));
652
        }
653
        // date doesn't match any standard
654
        return '';
655
    }
656
657
    /**
658
     * Remove appended "valueURI" from authors' names for indexing.
659
     *
660
     * @access private
661
     *
662
     * @static
663
     *
664
     * @param array|string $authors Array or string containing author/authors
665
     *
666
     * @return array|string
667
     */
668
    private static function removeAppendsFromAuthor($authors)
669
    {
670
        if (is_array($authors)) {
671
            foreach ($authors as $i => $author) {
672
                $splitName = explode(pack('C', 31), $author);
673
                $authors[$i] = $splitName[0];
674
            }
675
        }
676
        return $authors;
677
    }
678
679
    /**
680
     * Handle exception.
681
     *
682
     * @static
683
     *
684
     * @access private
685
     *
686
     * @param string $errorMessage
687
     *
688
     * @return void
689
     */
690
    private static function handleException(string $errorMessage): void
691
    {
692
        if (!(Environment::isCli())) {
693
            self::addErrorMessage(Helper::getLanguageService()->getLL('flash.solrException') . '<br />' . htmlspecialchars($errorMessage));
694
        }
695
        Helper::log('Apache Solr threw exception: "' . $errorMessage . '"', LOG_SEVERITY_ERROR);
696
    }
697
698
    /**
699
     * Add error message only with message content.
700
     *
701
     * @static
702
     *
703
     * @access private
704
     *
705
     * @param string $message
706
     *
707
     * @return void
708
     */
709
    private static function addErrorMessage(string $message): void
710
    {
711
        self::addMessage(
712
            $message,
713
            'flash.error',
714
            FlashMessage::ERROR
715
        );
716
    }
717
718
    /**
719
     * Add message only with changeable parameters.
720
     *
721
     * @static
722
     *
723
     * @access private
724
     *
725
     * @param string $message
726
     * @param string $type
727
     * @param int $status
728
     *
729
     * @return void
730
     */
731
    private static function addMessage(string $message, string $type, int $status): void
732
    {
733
        Helper::addMessage(
734
            $message,
735
            Helper::getLanguageService()->getLL($type),
736
            $status,
737
            true,
738
            'core.template.flashMessages'
739
        );
740
    }
741
742
    /**
743
     * Prevent instantiation by hiding the constructor
744
     *
745
     * @access private
746
     *
747
     * @return void
748
     */
749
    private function __construct()
750
    {
751
    }
752
}
753