Passed
Pull Request — master (#102)
by
unknown
09:05
created

BaseCommand::getParentDocumentUidForSaving()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 19
nc 7
nop 1
dl 0
loc 38
rs 9.0111
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\Command;
14
15
use Kitodo\Dlf\Common\Doc;
16
use Kitodo\Dlf\Common\Helper;
17
use Kitodo\Dlf\Common\Indexer;
18
use Kitodo\Dlf\Domain\Repository\CollectionRepository;
19
use Kitodo\Dlf\Domain\Repository\DocumentRepository;
20
use Kitodo\Dlf\Domain\Repository\LibraryRepository;
21
use Kitodo\Dlf\Domain\Repository\StructureRepository;
22
use Kitodo\Dlf\Domain\Model\Document;
23
use Kitodo\Dlf\Domain\Model\Library;
24
use Symfony\Component\Console\Command\Command;
25
use TYPO3\CMS\Core\Utility\GeneralUtility;
26
use TYPO3\CMS\Core\Utility\MathUtility;
27
use TYPO3\CMS\Core\Database\ConnectionPool;
28
use TYPO3\CMS\Core\Database\Connection;
29
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
30
use TYPO3\CMS\Extbase\Object\ObjectManager;
31
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
32
33
/**
34
 * Base class for CLI Command classes.
35
 *
36
 * @author Beatrycze Volk <[email protected]>
37
 * @package TYPO3
38
 * @subpackage dlf
39
 * @access public
40
 */
41
class BaseCommand extends Command
42
{
43
    /**
44
     * @var CollectionRepository
45
     */
46
    protected $collectionRepository;
47
48
    /**
49
     * @var DocumentRepository
50
     */
51
    protected $documentRepository;
52
53
    /**
54
     * @var LibraryRepository
55
     */
56
    protected $libraryRepository;
57
58
    /**
59
     * @var StructureRepository
60
     */
61
    protected $structureRepository;
62
63
    /**
64
     * @var int
65
     */
66
    protected $storagePid;
67
68
    /**
69
     * @var \Kitodo\Dlf\Domain\Model\Library
70
     */
71
    protected $owner;
72
73
    /**
74
     * Initialize the extbase repository based on the given storagePid.
75
     *
76
     * TYPO3 10+: Find a better solution e.g. based on Symfonie Dependancy Injection.
77
     *
78
     * @param int $storagePid The storage pid
79
     *
80
     * @return bool
81
     */
82
    protected function initializeRepositories($storagePid)
83
    {
84
        if (MathUtility::canBeInterpretedAsInteger($storagePid)) {
85
            $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
86
            $frameworkConfiguration = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
87
88
            $frameworkConfiguration['persistence']['storagePid'] = MathUtility::forceIntegerInRange((int) $storagePid, 0);
89
            $configurationManager->setConfiguration($frameworkConfiguration);
90
91
            // TODO: When we drop support for TYPO3v9, we needn't/shouldn't use ObjectManager anymore
92
            $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
93
94
            $this->collectionRepository = $objectManager->get(CollectionRepository::class);
95
            $this->documentRepository = $objectManager->get(DocumentRepository::class);
96
            $this->libraryRepository = $objectManager->get(LibraryRepository::class);
97
            $this->structureRepository = $objectManager->get(StructureRepository::class);
98
        } else {
99
            return false;
100
        }
101
        $this->storagePid = MathUtility::forceIntegerInRange((int) $storagePid, 0);
102
103
        return true;
104
    }
105
106
    /**
107
     * Return matching uid of Solr core depending on the input value.
108
     *
109
     * @param array $solrCores array of the valid Solr cores
110
     * @param string|bool|null $inputSolrId possible uid or name of Solr core
111
     *
112
     * @return int matching uid of Solr core
113
     */
114
    protected function getSolrCoreUid(array $solrCores, $inputSolrId): int
115
    {
116
        if (MathUtility::canBeInterpretedAsInteger($inputSolrId)) {
117
            $solrCoreUid = MathUtility::forceIntegerInRange((int) $inputSolrId, 0);
118
        } else {
119
            $solrCoreUid = $solrCores[$inputSolrId];
120
        }
121
        return $solrCoreUid;
122
    }
123
124
    /**
125
     * Fetches all Solr cores on given page.
126
     *
127
     * @param int $pageId The UID of the Solr core or 0 to disable indexing
128
     *
129
     * @return array Array of valid Solr cores
130
     */
131
    protected function getSolrCores(int $pageId): array
132
    {
133
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
134
            ->getQueryBuilderForTable('tx_dlf_solrcores');
135
136
        $solrCores = [];
137
        $result = $queryBuilder
138
            ->select('uid', 'index_name')
139
            ->from('tx_dlf_solrcores')
140
            ->where(
141
                $queryBuilder->expr()->eq(
142
                    'pid',
143
                    $queryBuilder->createNamedParameter((int) $pageId, Connection::PARAM_INT)
144
                )
145
            )
146
            ->execute();
147
148
        while ($record = $result->fetch()) {
149
            $solrCores[$record['index_name']] = $record['uid'];
150
        }
151
152
        return $solrCores;
153
    }
154
155
    /**
156
     * Update or insert document to database
157
     *
158
     * @param int|string $doc The document uid from DB OR the location of a mets document.
159
     *
160
     * @return bool true on success
161
     */
162
    protected function saveToDatabase(Document $document)
163
    {
164
        $success = false;
165
166
        $doc = $document->getDoc();
167
        if ($doc === null) {
168
            return $success;
169
        }
170
        $doc->cPid = $this->storagePid;
171
172
        $metadata = $doc->getTitledata($this->storagePid);
173
174
        // set title data
175
        $document->setTitle($metadata['title'][0] ? : '');
176
        $document->setTitleSorting($metadata['title_sorting'][0]);
177
        $document->setPlace(implode('; ', $metadata['place']));
178
        $document->setYear(implode('; ', $metadata['year']));
179
180
        // Remove appended "valueURI" from authors' names for storing in database.
181
        foreach ($metadata['author'] as $i => $author) {
182
            $splitName = explode(chr(31), $author);
183
            $metadata['author'][$i] = $splitName[0];
184
        }
185
        $document->setAuthor(implode('; ', $metadata['author']));
186
        $document->setThumbnail($doc->thumbnail ? : '');
187
        $document->setMetsLabel($metadata['mets_label'][0] ? : '');
188
        $document->setMetsOrderlabel($metadata['mets_orderlabel'][0] ? : '');
189
190
        $structure = $this->structureRepository->findOneByIndexName($metadata['type'][0], 'tx_dlf_structures');
0 ignored issues
show
Bug introduced by
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\StructureRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

190
        /** @scrutinizer ignore-call */ 
191
        $structure = $this->structureRepository->findOneByIndexName($metadata['type'][0], 'tx_dlf_structures');
Loading history...
191
        $document->setStructure($structure);
192
193
        $collections = $this->collectionRepository->findCollectionsBySettings(['index_name' => $metadata['collection']]);
194
        if ($collections) {
0 ignored issues
show
introduced by
$collections is of type TYPO3\CMS\Extbase\Persistence\QueryResultInterface, thus it always evaluated to true.
Loading history...
195
            foreach ($collections as $collection) {
196
                $document->addCollection($collection);
197
            }
198
        }
199
200
        // set identifiers
201
        $document->setProdId($metadata['prod_id'][0] ? : '');
202
        $document->setOpacId($metadata['opac_id'][0] ? : '');
203
        $document->setUnionId($metadata['union_id'][0] ? : '');
204
205
        $document->setRecordId($metadata['record_id'][0] ? : ''); // (?) $doc->recordId
206
        $document->setUrn($metadata['urn'][0] ? : '');
207
        $document->setPurl($metadata['purl'][0] ? : '');
208
        $document->setDocumentFormat($metadata['document_format'][0] ? : '');
209
210
        // set access
211
        $document->setLicense($metadata['license'][0] ? : '');
212
        $document->setTerms($metadata['terms'][0] ? : '');
213
        $document->setRestrictions($metadata['restrictions'][0] ? : '');
214
        $document->setOutOfPrint($metadata['out_of_print'][0] ? : '');
215
        $document->setRightsInfo($metadata['rights_info'][0] ? : '');
216
        $document->setStatus(0);
217
218
        if ($this->owner) {
219
            // library / owner is set by parameter --> take it.
220
            $document->setOwner($this->owner);
221
        } else {
222
            // owner is not set set but found by metadata --> take it or take default library
223
            $owner = $metadata['owner'][0] ? : 'default';
224
            $this->owner = $this->libraryRepository->findOneByIndexName($owner);
0 ignored issues
show
Bug introduced by
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\LibraryRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

224
            /** @scrutinizer ignore-call */ 
225
            $this->owner = $this->libraryRepository->findOneByIndexName($owner);
Loading history...
225
            if ($this->owner) {
226
                $document->setOwner($this->owner);
227
            } else {
228
                // create library
229
                $this->owner = GeneralUtility::makeInstance(Library::class);
230
231
                $this->owner->setLabel($owner);
232
                $this->owner->setIndexName($owner);
233
                $this->libraryRepository->add($this->owner);
234
                $document->setOwner($this->owner);
235
            }
236
        }
237
238
        // to be still (re-) implemented
239
        // 'volume' => $metadata['volume'][0],
240
        // 'volume_sorting' => $metadata['volume_sorting'][0],
241
242
        // Get UID of parent document.
243
        if ($document->getDocumentFormat() === 'METS') {
244
            $document->setPartof($this->getParentDocumentUidForSaving($document));
245
        }
246
247
        if ($document->getUid() === null) {
248
            // new document
249
            $this->documentRepository->add($document);
250
        } else {
251
            // update of existing document
252
            $this->documentRepository->update($document);
253
        }
254
255
        $persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class);
256
        $persistenceManager->persistAll();
257
258
        $success = true;
259
260
        return $success;
261
    }
262
263
    /**
264
     * Get the ID of the parent document if the current document has one.
265
     * Currently only applies to METS documents.
266
     *
267
     * @access protected
268
     *
269
     * @return int The parent document's id.
270
     */
271
    protected function getParentDocumentUidForSaving(Document $document)
272
    {
273
        $doc = $document->getDoc();
274
275
        if ($doc !== null) {
276
            // Get the closest ancestor of the current document which has a MPTR child.
277
            $parentMptr = $doc->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="' . $doc->toplevelId . '"]/ancestor::mets:div[./mets:mptr][1]/mets:mptr');
0 ignored issues
show
Bug Best Practice introduced by
The property mets does not exist on Kitodo\Dlf\Common\Doc. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The method xpath() does not exist on null. ( Ignorable by Annotation )

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

277
            /** @scrutinizer ignore-call */ 
278
            $parentMptr = $doc->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="' . $doc->toplevelId . '"]/ancestor::mets:div[./mets:mptr][1]/mets:mptr');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
278
            if (!empty($parentMptr)) {
279
                $parentLocation = (string) $parentMptr[0]->attributes('http://www.w3.org/1999/xlink')->href;
280
281
                // find document object by record_id of parent
282
                $parentDoc = Doc::getInstance($parentLocation, ['storagePid' => $this->storagePid]);
283
284
                if ($parentDoc->recordId) {
285
                    $parentDocument = $this->documentRepository->findOneByRecordId($parentDoc->recordId);
0 ignored issues
show
Bug introduced by
The method findOneByRecordId() does not exist on Kitodo\Dlf\Domain\Repository\DocumentRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

285
                    /** @scrutinizer ignore-call */ 
286
                    $parentDocument = $this->documentRepository->findOneByRecordId($parentDoc->recordId);
Loading history...
286
287
                    if ($parentDocument === null) {
288
                        // create new Document object
289
                        $parentDocument = GeneralUtility::makeInstance(Document::class);
290
                    }
291
292
                    $parentDocument->setOwner($this->owner);
0 ignored issues
show
Bug introduced by
The method setOwner() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

292
                    $parentDocument->/** @scrutinizer ignore-call */ 
293
                                     setOwner($this->owner);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
293
                    $parentDocument->setDoc($parentDoc);
0 ignored issues
show
Bug introduced by
The method setDoc() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

293
                    $parentDocument->/** @scrutinizer ignore-call */ 
294
                                     setDoc($parentDoc);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
294
                    $parentDocument->setLocation($parentLocation);
0 ignored issues
show
Bug introduced by
The method setLocation() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

294
                    $parentDocument->/** @scrutinizer ignore-call */ 
295
                                     setLocation($parentLocation);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
295
                    $parentDocument->setSolrcore($document->getSolrcore());
0 ignored issues
show
Bug introduced by
The method setSolrcore() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

295
                    $parentDocument->/** @scrutinizer ignore-call */ 
296
                                     setSolrcore($document->getSolrcore());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
296
297
                    $success = $this->saveToDatabase($parentDocument);
298
299
                    if ($success === true) {
300
                        // add to index
301
                        Indexer::add($parentDocument);
302
                        return $parentDocument->getUid();
0 ignored issues
show
Bug introduced by
The method getUid() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

302
                        return $parentDocument->/** @scrutinizer ignore-call */ getUid();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
303
                    }
304
                }
305
            }
306
        }
307
308
        return 0;
309
    }
310
311
}
312