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.
Completed
Push — master ( 90c912...99a750 )
by Sebastian
14s queued 11s
created

ext_update   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 437
Duplicated Lines 0 %

Importance

Changes 9
Bugs 2 Features 0
Metric Value
wmc 50
eloc 213
c 9
b 2
f 0
dl 0
loc 437
rs 8.4

12 Methods

Rating   Name   Duplication   Size   Complexity  
A access() 0 18 6
A main() 0 22 6
A renameIndexRelatedColumns() 0 28 2
A updateMetadataConfig() 0 54 5
A updateFormatClasses() 0 25 2
A oldFormatClasses() 0 20 2
A getMetadataConfig() 0 22 6
B oldIndexRelatedTableNames() 0 21 7
A hasNoFormatForDocument() 0 32 5
A solariumSolrUpdateRequired() 0 17 3
A updateDocumentAddFormat() 0 30 2
A doSolariumSolrUpdate() 0 29 4

How to fix   Complexity   

Complex Class

Complex classes like ext_update often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ext_update, and based on these observations, apply Extract Interface, too.

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
use Kitodo\Dlf\Common\Helper;
14
use Kitodo\Dlf\Common\Solr;
15
use TYPO3\CMS\Core\Database\ConnectionPool;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
18
/**
19
 * Update class 'ext_update' for the 'dlf' extension
20
 *
21
 * @author Sebastian Meyer <[email protected]>
22
 * @package TYPO3
23
 * @subpackage dlf
24
 * @access public
25
 */
26
class ext_update
27
{
28
    /**
29
     * This holds the output ready to return
30
     *
31
     * @var string
32
     * @access protected
33
     */
34
    protected $content = '';
35
36
    /**
37
     * Triggers the update option in the extension manager
38
     *
39
     * @access public
40
     *
41
     * @return bool Should the update option be shown?
42
     */
43
    public function access(): bool
44
    {
45
        if (count($this->getMetadataConfig())) {
46
            return true;
47
        }
48
        if ($this->oldIndexRelatedTableNames()) {
49
            return true;
50
        }
51
        if ($this->solariumSolrUpdateRequired()) {
52
            return true;
53
        }
54
        if (count($this->oldFormatClasses())) {
55
            return true;
56
        }
57
        if ($this->hasNoFormatForDocument()) {
58
            return true;
59
        }
60
        return false;
61
    }
62
63
    /**
64
     * The main method of the class
65
     *
66
     * @access public
67
     *
68
     * @return string The content that is displayed on the website
69
     */
70
    public function main(): string
71
    {
72
        // Load localization file.
73
        $GLOBALS['LANG']->includeLLFile('EXT:dlf/Resources/Private/Language/FlashMessages.xml');
74
        // Update the metadata configuration.
75
        if (count($this->getMetadataConfig())) {
76
            $this->updateMetadataConfig();
77
        }
78
        if ($this->oldIndexRelatedTableNames()) {
79
            $this->renameIndexRelatedColumns();
80
        }
81
        if ($this->solariumSolrUpdateRequired()) {
82
            $this->doSolariumSolrUpdate();
83
        }
84
        if (count($this->oldFormatClasses())) {
85
            $this->updateFormatClasses();
86
        }
87
        // Set tx_dlf_documents.document_format to distinguish between METS and IIIF.
88
        if ($this->hasNoFormatForDocument()) {
89
            $this->updateDocumentAddFormat();
90
        }
91
        return $this->content;
92
    }
93
94
    /**
95
     * Get all outdated metadata configuration records
96
     *
97
     * @access protected
98
     *
99
     * @return array Array of UIDs of outdated records
100
     */
101
    protected function getMetadataConfig(): array
102
    {
103
        $uids = [];
104
        // check if tx_dlf_metadata.xpath exists anyhow
105
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_metadata');
106
107
        $result = $queryBuilder
108
            ->select('*')
109
            ->from('tx_dlf_metadata')
110
            ->execute();
111
112
        $rows = $result->fetchAll();
113
114
        if ((count($rows) === 0) || !array_key_exists('xpath', $rows[0])) {
115
            return $uids;
116
        }
117
        foreach ($rows as $row) {
118
            if ($row['format'] === 0 && $row['xpath']) {
119
                $uids[] = (int)$row['uid'];
120
            }
121
        }
122
        return $uids;
123
    }
124
125
    /**
126
     * Check all configured Solr cores
127
     *
128
     * @access protected
129
     *
130
     * @return bool
131
     */
132
    protected function solariumSolrUpdateRequired(): bool
133
    {
134
        // Get all Solr cores that were not deleted.
135
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_solrcores');
136
        $result = $queryBuilder
137
            ->select('index_name')
138
            ->from('tx_dlf_solrcores')
139
            ->execute();
140
141
        while ($resArray = $result->fetch()) {
142
            // Instantiate search object.
143
            $solr = Solr::getInstance($resArray['index_name']);
144
            if (!$solr->ready) {
145
                return true;
146
            }
147
        }
148
        return false;
149
    }
150
151
    /**
152
     * Check for old format classes
153
     *
154
     * @access protected
155
     *
156
     * @return array containing old format classes
157
     */
158
    protected function oldFormatClasses(): array
159
    {
160
        $oldRecords = [];
161
        // Get all records with outdated configuration.
162
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_formats');
163
164
        $result = $queryBuilder
165
            ->select('tx_dlf_formats.uid AS uid', 'tx_dlf_formats.type AS type')
166
            ->from('tx_dlf_formats')
167
            ->where(
168
                $queryBuilder->expr()->isNotNull('tx_dlf_formats.class'),
169
                $queryBuilder->expr()->neq('tx_dlf_formats.class', $queryBuilder->createNamedParameter('')),
170
                $queryBuilder->expr()->like('tx_dlf_formats.class', $queryBuilder->createNamedParameter('%tx_dlf_%'))
171
            )
172
            ->execute();
173
        while ($resArray = $result->fetch()) {
174
            $oldRecords[$resArray['uid']] = $resArray['type'];
175
        }
176
177
        return $oldRecords;
178
    }
179
180
    /**
181
     * Check for old index related columns
182
     *
183
     * @access protected
184
     *
185
     * @return bool true if old index related columns exist
186
     */
187
    protected function oldIndexRelatedTableNames(): bool
188
    {
189
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('INFORMATION_SCHEMA.COLUMNS');
190
191
        $result = $queryBuilder
192
            ->select('column_name')
193
            ->from('INFORMATION_SCHEMA.COLUMNS')
194
            ->where('TABLE_NAME = "tx_dlf_metadata"')
195
            ->execute();
196
        while ($resArray = $result->fetch()) {
197
            if (
198
                $resArray['column_name'] === 'tokenized'
199
                || $resArray['column_name'] === 'stored'
200
                || $resArray['column_name'] === 'indexed'
201
                || $resArray['column_name'] === 'boost'
202
                || $resArray['column_name'] === 'autocomplete'
203
            ) {
204
                return true;
205
            }
206
        }
207
        return false;
208
    }
209
210
    /**
211
     * check if document has format
212
     *
213
     * @access protected
214
     * @param bool $checkStructureOnly
215
     * @return bool
216
     */
217
    protected function hasNoFormatForDocument($checkStructureOnly = false): bool
218
    {
219
        // Check if column "document_format" exists.
220
        $database = $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['dbname'];
221
222
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('INFORMATION_SCHEMA.COLUMNS');
223
224
        $result = $queryBuilder
225
            ->select('COLUMN_NAME')
226
            ->from('INFORMATION_SCHEMA.COLUMNS')
227
            ->where('TABLE_NAME="tx_dlf_documents" AND TABLE_SCHEMA="' . $database . '" AND COLUMN_NAME="document_format"')
228
            ->execute();
229
        while ($resArray = $result->fetch()) {
230
            if ($resArray['COLUMN_NAME'] === 'document_format') {
231
                if ($checkStructureOnly) {
232
                    return false;
233
                }
234
                // Check if column has empty fields.
235
                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('INFORMATION_SCHEMA.COLUMNS');
236
                $count = $queryBuilder
237
                    ->count('uid')
238
                    ->from('tx_dlf_documents')
239
                    ->where('document_format="" OR document_format IS NULL')
240
                    ->execute()
241
                    ->fetchColumn(0);
242
243
                if ($count === 0) {
244
                    return false;
245
                }
246
            }
247
        }
248
        return true;
249
    }
250
251
    /**
252
     * Copy the data of the old index related columns to the new columns
253
     *
254
     * @access protected
255
     *
256
     * @return void
257
     */
258
    protected function renameIndexRelatedColumns(): void
259
    {
260
261
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_metadata');
262
263
        $result = $queryBuilder
264
            ->update('tx_dlf_metadata', 'm')
265
            ->set('m.index_tokenized', 'm.tokenized')
266
            ->set('m.index_stored', 'm.stored')
267
            ->set('m.index_indexed', 'm.indexed')
268
            ->set('m.index_boost', 'm.boost')
269
            ->set('m.index_autocomplete', 'm.autocomplete')
270
            ->execute();
271
272
        if ($result) {
273
            Helper::addMessage(
274
                htmlspecialchars($GLOBALS['LANG']->getLL('update.copyIndexRelatedColumnsOkay')),
275
                htmlspecialchars($GLOBALS['LANG']->getLL('update.copyIndexRelatedColumns')),
276
                \TYPO3\CMS\Core\Messaging\FlashMessage::OK
277
            );
278
        } else {
279
            Helper::addMessage(
280
                htmlspecialchars($GLOBALS['LANG']->getLL('update.copyIndexRelatedColumnsNotOkay')),
281
                htmlspecialchars($GLOBALS['LANG']->getLL('update.copyIndexRelatedColumns')),
282
                \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING
283
            );
284
        }
285
        $this->content .= Helper::renderFlashMessages();
286
    }
287
288
    /**
289
     * Update all outdated format records
290
     *
291
     * @access protected
292
     *
293
     * @return void
294
     */
295
    protected function updateFormatClasses(): void
296
    {
297
        $oldRecords = $this->oldFormatClasses();
298
        $newValues = [
299
            'ALTO' => 'Kitodo\\\\Dlf\\\\Format\\\\Alto', // Those are effectively single backslashes
300
            'MODS' => 'Kitodo\\\\Dlf\\\\Format\\\\Mods',
301
            'TEIHDR' => 'Kitodo\\\\Dlf\\\\Format\\\\TeiHeader'
302
        ];
303
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_formats');
304
305
        foreach ($oldRecords as $uid => $type) {
306
            $queryBuilder
307
                ->update('tx_dlf_formats')
308
                ->where(
309
                    $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))
310
                )
311
                ->set('class', $newValues[$type])
312
                ->execute();
313
        }
314
        Helper::addMessage(
315
            htmlspecialchars($GLOBALS['LANG']->getLL('update.FormatClassesOkay')),
316
            htmlspecialchars($GLOBALS['LANG']->getLL('update.FormatClasses')),
317
            \TYPO3\CMS\Core\Messaging\FlashMessage::OK
318
        );
319
        $this->content .= Helper::renderFlashMessages();
320
    }
321
322
    /**
323
     * Update all outdated metadata configuration records
324
     *
325
     * @access protected
326
     *
327
     * @return void
328
     */
329
    protected function updateMetadataConfig(): void
330
    {
331
        $metadataUids = $this->getMetadataConfig();
332
        if (!empty($metadataUids)) {
333
            $data = [];
334
335
            // Get all old metadata configuration records.
336
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_metadata');
337
            $result = $queryBuilder
338
                ->select('tx_dlf_metadata.uid AS uid', 'tx_dlf_metadata.pid AS pid', 'tx_dlf_metadata.cruser_id AS cruser_id', 'tx_dlf_metadata.encoded AS encoded', 'tx_dlf_metadata.xpath AS xpath', 'tx_dlf_metadata.xpath_sorting AS xpath_sorting')
339
                ->from('tx_dlf_metadata')
340
                ->where(
341
                    $queryBuilder->expr()->in(
342
                        'tx_dlf_metadata.uid',
343
                        $queryBuilder->createNamedParameter(
344
                            $metadataUids,
345
                            \TYPO3\CMS\Core\Database\Connection::PARAM_INT_ARRAY
346
                        )
347
                    )
348
                )
349
                ->execute();
350
351
            while ($resArray = $result->fetch()) {
352
                $newId = uniqid('NEW');
353
                // Copy record to new table.
354
                $data['tx_dlf_metadataformat'][$newId] = [
355
                    'pid' => $resArray['pid'],
356
                    'cruser_id' => $resArray['cruser_id'],
357
                    'parent_id' => $resArray['uid'],
358
                    'encoded' => $resArray['encoded'],
359
                    'xpath' => $resArray['xpath'],
360
                    'xpath_sorting' => $resArray['xpath_sorting']
361
                ];
362
                // Add reference to old table.
363
                $data['tx_dlf_metadata'][$resArray['uid']]['format'] = $newId;
364
            }
365
            if (!empty($data)) {
366
                // Process datamap.
367
                $substUids = Helper::processDBasAdmin($data);
368
                unset($data);
369
                if (!empty($substUids)) {
370
                    Helper::addMessage(
371
                        htmlspecialchars($GLOBALS['LANG']->getLL('update.metadataConfigOkay')),
372
                        htmlspecialchars($GLOBALS['LANG']->getLL('update.metadataConfig')),
373
                        \TYPO3\CMS\Core\Messaging\FlashMessage::OK
374
                    );
375
                } else {
376
                    Helper::addMessage(
377
                        htmlspecialchars($GLOBALS['LANG']->getLL('update.metadataConfigNotOkay')),
378
                        htmlspecialchars($GLOBALS['LANG']->getLL('update.metadataConfig')),
379
                        \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING
380
                    );
381
                }
382
                $this->content .= Helper::renderFlashMessages();
383
            }
384
        }
385
    }
386
387
388
389
    /**
390
     * Create all configured Solr cores
391
     *
392
     * @access protected
393
     *
394
     * @return void
395
     */
396
    protected function doSolariumSolrUpdate(): void
397
    {
398
        $error = false;
399
        // Get all Solr cores that were not deleted.
400
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_solrcores');
401
        $result = $queryBuilder
402
            ->select('index_name')
403
            ->from('tx_dlf_solrcores')
404
            ->execute();
405
406
        while ($resArray = $result->fetch()) {
407
            // Create core if it doesn't exist.
408
            if (Solr::createCore($resArray['index_name']) !== $resArray['index_name']) {
409
                Helper::addMessage(
410
                    htmlspecialchars($GLOBALS['LANG']->getLL('update.solariumSolrUpdateNotOkay')),
411
                    htmlspecialchars(sprintf($GLOBALS['LANG']->getLL('update.solariumSolrUpdate'), $resArray['index_name'])),
412
                    \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR
413
                );
414
                $this->content .= Helper::renderFlashMessages();
415
                $error = true;
416
            }
417
        }
418
        if (!$error) {
419
            Helper::addMessage(
420
                htmlspecialchars($GLOBALS['LANG']->getLL('update.solariumSolrUpdateOkay')),
421
                htmlspecialchars($GLOBALS['LANG']->getLL('update.solariumSolrUpdate')),
422
                \TYPO3\CMS\Core\Messaging\FlashMessage::OK
423
            );
424
            $this->content .= Helper::renderFlashMessages();
425
        }
426
    }
427
428
    /**
429
     * Add format type to outdated tx_dlf_documents rows
430
     *
431
     * @return void
432
     */
433
    protected function updateDocumentAddFormat(): void
434
    {
435
436
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_dlf_documents');
437
438
        $result = $queryBuilder
439
            ->update('tx_dlf_documents')
440
            ->where(
441
                $queryBuilder->expr()->orX(
442
                    $queryBuilder->expr()->eq('document_format', $queryBuilder->createNamedParameter(null)),
443
                    $queryBuilder->expr()->eq('document_format', $queryBuilder->createNamedParameter(''))
444
                )
445
            )
446
            ->set('document_format', 'METS')
447
            ->execute();
448
449
        if ($result) {
450
            Helper::addMessage(
451
                htmlspecialchars($GLOBALS['LANG']->getLL('update.documentSetFormatForOldEntriesOkay')),
452
                htmlspecialchars($GLOBALS['LANG']->getLL('update.documentSetFormatForOldEntries')),
453
                \TYPO3\CMS\Core\Messaging\FlashMessage::OK
454
            );
455
        } else {
456
            Helper::addMessage(
457
                htmlspecialchars($GLOBALS['LANG']->getLL('update.documentSetFormatForOldEntriesNotOkay')),
458
                htmlspecialchars($GLOBALS['LANG']->getLL('update.documentSetFormatForOldEntries')),
459
                \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING
460
            );
461
        }
462
        $this->content .= Helper::renderFlashMessages();
463
    }
464
}
465