We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.
1 | <?php |
||
2 | /** |
||
3 | * (c) Kitodo. Key to digital objects e.V. <[email protected]> |
||
4 | * |
||
5 | * This file is part of the Kitodo and TYPO3 projects. |
||
6 | * |
||
7 | * @license GNU General Public License version 3 or later. |
||
8 | * For the full copyright and license information, please read the |
||
9 | * LICENSE.txt file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Kitodo\Dlf\Controller\Backend; |
||
13 | |||
14 | use Kitodo\Dlf\Common\Helper; |
||
15 | use Kitodo\Dlf\Common\Solr\Solr; |
||
16 | use Kitodo\Dlf\Controller\AbstractController; |
||
17 | use Kitodo\Dlf\Domain\Model\Format; |
||
18 | use Kitodo\Dlf\Domain\Model\SolrCore; |
||
19 | use Kitodo\Dlf\Domain\Repository\FormatRepository; |
||
20 | use Kitodo\Dlf\Domain\Repository\MetadataRepository; |
||
21 | use Kitodo\Dlf\Domain\Repository\SolrCoreRepository; |
||
22 | use Kitodo\Dlf\Domain\Repository\StructureRepository; |
||
23 | use Psr\Http\Message\ResponseInterface; |
||
24 | use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; |
||
25 | use TYPO3\CMS\Backend\Utility\BackendUtility; |
||
26 | use TYPO3\CMS\Core\Core\Environment; |
||
27 | use TYPO3\CMS\Core\Exception\SiteNotFoundException; |
||
28 | use TYPO3\CMS\Core\Localization\LocalizationFactory; |
||
29 | use TYPO3\CMS\Core\Messaging\FlashMessageService; |
||
30 | use TYPO3\CMS\Core\Page\PageRenderer; |
||
31 | use TYPO3\CMS\Core\Resource\ResourceFactory; |
||
32 | use TYPO3\CMS\Core\Site\Entity\NullSite; |
||
33 | use TYPO3\CMS\Core\Site\SiteFinder; |
||
34 | use TYPO3\CMS\Core\Utility\GeneralUtility; |
||
35 | use TYPO3\CMS\Extbase\Mvc\Request; |
||
36 | use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; |
||
37 | use TYPO3\CMS\Fluid\View\TemplateView; |
||
38 | use TYPO3Fluid\Fluid\View\ViewInterface; |
||
39 | |||
40 | /** |
||
41 | * Controller class for the backend module 'New Tenant'. |
||
42 | * |
||
43 | * @package TYPO3 |
||
44 | * @subpackage dlf |
||
45 | * |
||
46 | * @access public |
||
47 | */ |
||
48 | class NewTenantController extends AbstractController |
||
49 | { |
||
50 | /** |
||
51 | * @access protected |
||
52 | * @var int |
||
53 | */ |
||
54 | protected int $pid; |
||
55 | |||
56 | /** |
||
57 | * @access protected |
||
58 | * @var array |
||
59 | */ |
||
60 | protected array $pageInfo; |
||
61 | |||
62 | /** |
||
63 | * @access protected |
||
64 | * @var array All configured site languages |
||
65 | */ |
||
66 | protected array $siteLanguages; |
||
67 | |||
68 | /** |
||
69 | * @access protected |
||
70 | * @var LocalizationFactory Language factory to get language key/values by our own. |
||
71 | */ |
||
72 | protected LocalizationFactory $languageFactory; |
||
73 | |||
74 | /** |
||
75 | * @access protected |
||
76 | * @var FormatRepository |
||
77 | */ |
||
78 | protected FormatRepository $formatRepository; |
||
79 | |||
80 | /** |
||
81 | * @access public |
||
82 | * |
||
83 | * @param FormatRepository $formatRepository |
||
84 | * |
||
85 | * @return void |
||
86 | */ |
||
87 | public function injectFormatRepository(FormatRepository $formatRepository): void |
||
88 | { |
||
89 | $this->formatRepository = $formatRepository; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @access protected |
||
94 | * @var MetadataRepository |
||
95 | */ |
||
96 | protected MetadataRepository $metadataRepository; |
||
97 | |||
98 | /** |
||
99 | * @access public |
||
100 | * |
||
101 | * @param MetadataRepository $metadataRepository |
||
102 | * |
||
103 | * @return void |
||
104 | */ |
||
105 | public function injectMetadataRepository(MetadataRepository $metadataRepository): void |
||
106 | { |
||
107 | $this->metadataRepository = $metadataRepository; |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * @access protected |
||
112 | * @var StructureRepository |
||
113 | */ |
||
114 | protected StructureRepository $structureRepository; |
||
115 | |||
116 | /** |
||
117 | * @access public |
||
118 | * |
||
119 | * @param StructureRepository $structureRepository |
||
120 | * |
||
121 | * @return void |
||
122 | */ |
||
123 | public function injectStructureRepository(StructureRepository $structureRepository): void |
||
124 | { |
||
125 | $this->structureRepository = $structureRepository; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @access protected |
||
130 | * @var SolrCoreRepository |
||
131 | */ |
||
132 | protected SolrCoreRepository $solrCoreRepository; |
||
133 | |||
134 | /** |
||
135 | * @access public |
||
136 | * |
||
137 | * @param SolrCoreRepository $solrCoreRepository |
||
138 | * |
||
139 | * @return void |
||
140 | */ |
||
141 | public function injectSolrCoreRepository(SolrCoreRepository $solrCoreRepository): void |
||
142 | { |
||
143 | $this->solrCoreRepository = $solrCoreRepository; |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Returns a response object with either the given html string or the current rendered view as content. |
||
148 | * |
||
149 | * @access protected |
||
150 | * |
||
151 | * @param ?string $html optional html |
||
152 | * |
||
153 | * @return ResponseInterface the response |
||
154 | */ |
||
155 | protected function htmlResponse(?string $html = null): ResponseInterface |
||
156 | { |
||
157 | $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); |
||
158 | $messageQueue = $flashMessageService->getMessageQueueByIdentifier(); |
||
159 | |||
160 | $moduleTemplateFactory = GeneralUtility::makeInstance(ModuleTemplateFactory::class); |
||
161 | $moduleTemplate = $moduleTemplateFactory->create($this->request); |
||
162 | $moduleTemplate->setContent($this->view->render()); |
||
163 | $moduleTemplate->setFlashMessageQueue($messageQueue); |
||
164 | return parent::htmlResponse(($html ?? $moduleTemplate->renderContent())); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Initialization for all actions |
||
169 | * |
||
170 | * @access protected |
||
171 | * |
||
172 | * @return void |
||
173 | */ |
||
174 | protected function initializeAction(): void |
||
175 | { |
||
176 | // replace with $this->request->getQueryParams() when dropping support for Typo3 v11, see Deprecation-100596 |
||
177 | $this->pid = (int) GeneralUtility::_GP('id'); |
||
178 | |||
179 | $frameworkConfiguration = $this->configurationManager->getConfiguration($this->configurationManager::CONFIGURATION_TYPE_FRAMEWORK); |
||
180 | $frameworkConfiguration['persistence']['storagePid'] = $this->pid; |
||
181 | $this->configurationManager->setConfiguration($frameworkConfiguration); |
||
182 | |||
183 | $this->languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class); |
||
184 | |||
185 | try { |
||
186 | $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($this->pid); |
||
187 | } catch (SiteNotFoundException $e) { |
||
188 | $site = new NullSite(); |
||
189 | } |
||
190 | $this->siteLanguages = $site->getLanguages(); |
||
191 | } |
||
192 | |||
193 | |||
194 | /** |
||
195 | * Action adding formats records |
||
196 | * |
||
197 | * @access public |
||
198 | * |
||
199 | * @return ResponseInterface the response |
||
200 | */ |
||
201 | public function addFormatAction(): ResponseInterface |
||
202 | { |
||
203 | // Include formats definition file. |
||
204 | $formatsDefaults = $this->getRecords('Format'); |
||
205 | |||
206 | $frameworkConfiguration = $this->configurationManager->getConfiguration($this->configurationManager::CONFIGURATION_TYPE_FRAMEWORK); |
||
207 | // tx_dlf_formats are stored on PID = 0 |
||
208 | $frameworkConfiguration['persistence']['storagePid'] = 0; |
||
209 | $this->configurationManager->setConfiguration($frameworkConfiguration); |
||
210 | |||
211 | $doPersist = false; |
||
212 | |||
213 | foreach ($formatsDefaults as $type => $values) { |
||
214 | // if default format record is not found, add it to the repository |
||
215 | if ($this->formatRepository->findOneByType($type) === null) { |
||
216 | $newRecord = GeneralUtility::makeInstance(Format::class); |
||
217 | $newRecord->setType($type); |
||
218 | $newRecord->setRoot($values['root']); |
||
219 | $newRecord->setNamespace($values['namespace']); |
||
220 | $newRecord->setClass($values['class']); |
||
221 | $this->formatRepository->add($newRecord); |
||
222 | |||
223 | $doPersist = true; |
||
224 | } |
||
225 | } |
||
226 | |||
227 | // We must persist here, if we changed anything. |
||
228 | if ($doPersist === true) { |
||
229 | $persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); |
||
230 | $persistenceManager->persistAll(); |
||
231 | } |
||
232 | |||
233 | return $this->redirect('index'); |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * Action adding metadata records |
||
238 | * |
||
239 | * @access public |
||
240 | * |
||
241 | * @return ResponseInterface the response |
||
242 | */ |
||
243 | public function addMetadataAction(): ResponseInterface |
||
244 | { |
||
245 | // Include metadata definition file. |
||
246 | $metadataDefaults = $this->getRecords('Metadata'); |
||
247 | |||
248 | // load language file in own array |
||
249 | $metadataLabels = $this->languageFactory->getParsedData('EXT:dlf/Resources/Private/Language/locallang_metadata.xlf', $this->siteLanguages[0]->getTypo3Language()); |
||
250 | |||
251 | $insertedFormats = $this->formatRepository->findAll(); |
||
252 | |||
253 | $availableFormats = []; |
||
254 | foreach ($insertedFormats as $insertedFormat) { |
||
255 | $availableFormats[$insertedFormat->getRoot()] = $insertedFormat->getUid(); |
||
256 | } |
||
257 | |||
258 | $defaultWrap = BackendUtility::getTcaFieldConfiguration('tx_dlf_metadata', 'wrap')['default']; |
||
259 | |||
260 | $data = []; |
||
261 | foreach ($metadataDefaults as $indexName => $values) { |
||
262 | $formatIds = []; |
||
263 | |||
264 | foreach ($values['format'] as $format) { |
||
265 | $format['encoded'] = $availableFormats[$format['format_root']]; |
||
266 | unset($format['format_root']); |
||
267 | $formatIds[] = uniqid('NEW'); |
||
268 | $data['tx_dlf_metadataformat'][end($formatIds)] = $format; |
||
269 | $data['tx_dlf_metadataformat'][end($formatIds)]['pid'] = $this->pid; |
||
270 | } |
||
271 | |||
272 | $data['tx_dlf_metadata'][uniqid('NEW')] = [ |
||
273 | 'pid' => $this->pid, |
||
274 | 'label' => $this->getLLL('metadata.' . $indexName, $this->siteLanguages[0]->getTypo3Language(), $metadataLabels), |
||
275 | 'index_name' => $indexName, |
||
276 | 'format' => implode(',', $formatIds), |
||
277 | 'default_value' => $values['default_value'], |
||
278 | 'wrap' => !empty($values['wrap']) ? $values['wrap'] : $defaultWrap, |
||
279 | 'index_tokenized' => $values['index_tokenized'], |
||
280 | 'index_stored' => $values['index_stored'], |
||
281 | 'index_indexed' => $values['index_indexed'], |
||
282 | 'index_boost' => $values['index_boost'], |
||
283 | 'is_sortable' => $values['is_sortable'], |
||
284 | 'is_facet' => $values['is_facet'], |
||
285 | 'is_listed' => $values['is_listed'], |
||
286 | 'index_autocomplete' => $values['index_autocomplete'], |
||
287 | ]; |
||
288 | } |
||
289 | |||
290 | $metadataIds = Helper::processDatabaseAsAdmin($data, [], true); |
||
291 | |||
292 | $insertedMetadata = []; |
||
293 | foreach ($metadataIds as $id => $uid) { |
||
294 | $metadata = $this->metadataRepository->findByUid($uid); |
||
295 | // id array contains also ids of formats |
||
296 | if ($metadata != null) { |
||
297 | $insertedMetadata[$uid] = $metadata->getIndexName(); |
||
298 | } |
||
299 | } |
||
300 | |||
301 | foreach ($this->siteLanguages as $siteLanguage) { |
||
302 | if ($siteLanguage->getLanguageId() === 0) { |
||
303 | // skip default language |
||
304 | continue; |
||
305 | } |
||
306 | |||
307 | $translateData = []; |
||
308 | foreach ($insertedMetadata as $id => $indexName) { |
||
309 | $translateData['tx_dlf_metadata'][uniqid('NEW')] = [ |
||
310 | 'pid' => $this->pid, |
||
311 | 'sys_language_uid' => $siteLanguage->getLanguageId(), |
||
312 | 'l18n_parent' => $id, |
||
313 | 'label' => $this->getLLL('metadata.' . $indexName, $siteLanguage->getTypo3Language(), $metadataLabels), |
||
314 | ]; |
||
315 | } |
||
316 | |||
317 | Helper::processDatabaseAsAdmin($translateData); |
||
318 | } |
||
319 | |||
320 | return $this->redirect('index'); |
||
321 | } |
||
322 | |||
323 | /** |
||
324 | * Action adding Solr core records |
||
325 | * |
||
326 | * @access public |
||
327 | * |
||
328 | * @return ResponseInterface the response |
||
329 | */ |
||
330 | public function addSolrCoreAction(): ResponseInterface |
||
331 | { |
||
332 | $doPersist = false; |
||
333 | |||
334 | // load language file in own array |
||
335 | $beLabels = $this->languageFactory->getParsedData('EXT:dlf/Resources/Private/Language/locallang_be.xlf', $this->siteLanguages[0]->getTypo3Language()); |
||
336 | |||
337 | if ($this->solrCoreRepository->findOneByPid($this->pid) === null) { |
||
338 | $newRecord = GeneralUtility::makeInstance(SolrCore::class); |
||
339 | $newRecord->setLabel($this->getLLL('flexform.solrcore', $this->siteLanguages[0]->getTypo3Language(), $beLabels). ' (PID ' . $this->pid . ')'); |
||
340 | $indexName = Solr::createCore(''); |
||
341 | if (!empty($indexName)) { |
||
342 | $newRecord->setIndexName($indexName); |
||
343 | |||
344 | $this->solrCoreRepository->add($newRecord); |
||
345 | |||
346 | $doPersist = true; |
||
347 | } |
||
348 | } |
||
349 | |||
350 | // We must persist here, if we changed anything. |
||
351 | if ($doPersist === true) { |
||
352 | $persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); |
||
353 | $persistenceManager->persistAll(); |
||
354 | } |
||
355 | |||
356 | return $this->redirect('index'); |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * Action adding structure records |
||
361 | * |
||
362 | * @access public |
||
363 | * |
||
364 | * @return ResponseInterface the response |
||
365 | */ |
||
366 | public function addStructureAction(): ResponseInterface |
||
367 | { |
||
368 | // Include structure definition file. |
||
369 | $structureDefaults = $this->getRecords('Structure'); |
||
370 | |||
371 | // load language file in own array |
||
372 | $structureLabels = $this->languageFactory->getParsedData('EXT:dlf/Resources/Private/Language/locallang_structure.xlf', $this->siteLanguages[0]->getTypo3Language()); |
||
373 | |||
374 | $data = []; |
||
375 | foreach ($structureDefaults as $indexName => $values) { |
||
376 | $data['tx_dlf_structures'][uniqid('NEW')] = [ |
||
377 | 'pid' => $this->pid, |
||
378 | 'toplevel' => $values['toplevel'], |
||
379 | 'label' => $this->getLLL('structure.' . $indexName, $this->siteLanguages[0]->getTypo3Language(), $structureLabels), |
||
380 | 'index_name' => $indexName, |
||
381 | 'oai_name' => $values['oai_name'], |
||
382 | 'thumbnail' => 0, |
||
383 | ]; |
||
384 | } |
||
385 | $structureIds = Helper::processDatabaseAsAdmin($data, [], true); |
||
386 | |||
387 | $insertedStructures = []; |
||
388 | foreach ($structureIds as $id => $uid) { |
||
389 | $insertedStructures[$uid] = $this->structureRepository->findByUid($uid)->getIndexName(); |
||
390 | } |
||
391 | |||
392 | foreach ($this->siteLanguages as $siteLanguage) { |
||
393 | if ($siteLanguage->getLanguageId() === 0) { |
||
394 | // skip default language |
||
395 | continue; |
||
396 | } |
||
397 | |||
398 | $translateData = []; |
||
399 | foreach ($insertedStructures as $id => $indexName) { |
||
400 | $translateData['tx_dlf_structures'][uniqid('NEW')] = [ |
||
401 | 'pid' => $this->pid, |
||
402 | 'sys_language_uid' => $siteLanguage->getLanguageId(), |
||
403 | 'l18n_parent' => $id, |
||
404 | 'label' => $this->getLLL('structure.' . $indexName, $siteLanguage->getTypo3Language(), $structureLabels), |
||
405 | ]; |
||
406 | } |
||
407 | |||
408 | Helper::processDatabaseAsAdmin($translateData); |
||
409 | } |
||
410 | |||
411 | return $this->redirect('index'); |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Main function of the module |
||
416 | * |
||
417 | * @access public |
||
418 | * |
||
419 | * @return ResponseInterface the response |
||
420 | */ |
||
421 | public function indexAction(): ResponseInterface |
||
422 | { |
||
423 | $recordInfos = []; |
||
424 | |||
425 | $this->pageInfo = BackendUtility::readPageAccess($this->pid, $GLOBALS['BE_USER']->getPagePermsClause(1)); |
||
0 ignored issues
–
show
|
|||
426 | |||
427 | if (!isset($this->pageInfo['doktype']) || $this->pageInfo['doktype'] != 254) { |
||
428 | return $this->redirect('error'); |
||
429 | } |
||
430 | |||
431 | $formatsDefaults = $this->getRecords('Format'); |
||
432 | $recordInfos['formats']['numCurrent'] = $this->formatRepository->countAll(); |
||
433 | $recordInfos['formats']['numDefault'] = count($formatsDefaults); |
||
434 | |||
435 | $structuresDefaults = $this->getRecords('Structure'); |
||
436 | $recordInfos['structures']['numCurrent'] = $this->structureRepository->countByPid($this->pid); |
||
437 | $recordInfos['structures']['numDefault'] = count($structuresDefaults); |
||
438 | |||
439 | $metadataDefaults = $this->getRecords('Metadata'); |
||
440 | $recordInfos['metadata']['numCurrent'] = $this->metadataRepository->countByPid($this->pid); |
||
441 | $recordInfos['metadata']['numDefault'] = count($metadataDefaults); |
||
442 | |||
443 | $recordInfos['solrcore']['numCurrent'] = $this->solrCoreRepository->countByPid($this->pid); |
||
444 | |||
445 | $this->view->assign('recordInfos', $recordInfos); |
||
446 | |||
447 | return $this->htmlResponse(); |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * Error function - there is nothing to do at the moment. |
||
452 | * |
||
453 | * @access public |
||
454 | * |
||
455 | * @return void |
||
456 | */ |
||
457 | // @phpstan-ignore-next-line |
||
458 | public function errorAction(): ResponseInterface |
||
459 | { |
||
460 | return $this->htmlResponse(); |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * Get language label for given key and language. |
||
465 | * |
||
466 | * @access private |
||
467 | * |
||
468 | * @param string $index |
||
469 | * @param string $lang |
||
470 | * @param array $langArray |
||
471 | * |
||
472 | * @return string |
||
473 | */ |
||
474 | private function getLLL(string $index, string $lang, array $langArray): string |
||
475 | { |
||
476 | if (isset($langArray[$lang][$index][0]['target'])) { |
||
477 | return $langArray[$lang][$index][0]['target']; |
||
478 | } elseif (isset($langArray['default'][$index][0]['target'])) { |
||
479 | return $langArray['default'][$index][0]['target']; |
||
480 | } else { |
||
481 | return 'Missing translation for ' . $index; |
||
482 | } |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Get records from file for given record type. |
||
487 | * |
||
488 | * @access private |
||
489 | * |
||
490 | * @param string $recordType |
||
491 | * |
||
492 | * @return array |
||
493 | */ |
||
494 | private function getRecords(string $recordType): array |
||
495 | { |
||
496 | $filePath = GeneralUtility::getFileAbsFileName('EXT:dlf/Resources/Private/Data/' . $recordType . 'Defaults.json'); |
||
497 | if (file_exists($filePath)) { |
||
498 | $fileContents = file_get_contents($filePath); |
||
499 | $records = json_decode($fileContents, true); |
||
500 | |||
501 | if (json_last_error() === JSON_ERROR_NONE) { |
||
502 | return $records; |
||
503 | } |
||
504 | } |
||
505 | return []; |
||
506 | } |
||
507 | } |
||
508 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.