1<?php 2namespace TYPO3\CMS\Extensionmanager\Utility; 3 4/* 5 * This file is part of the TYPO3 CMS project. 6 * 7 * It is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License, either version 2 9 * of the License, or any later version. 10 * 11 * For the full copyright and license information, please read the 12 * LICENSE.txt file that was distributed with this source code. 13 * 14 * The TYPO3 project - inspiring people to share! 15 */ 16 17use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; 18use TYPO3\CMS\Core\Core\Environment; 19use TYPO3\CMS\Core\Database\Schema\SchemaMigrator; 20use TYPO3\CMS\Core\Database\Schema\SqlReader; 21use TYPO3\CMS\Core\Service\OpcodeCacheService; 22use TYPO3\CMS\Core\Utility\GeneralUtility; 23use TYPO3\CMS\Extensionmanager\Domain\Model\Extension; 24use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException; 25use TYPO3\CMS\Impexp\Utility\ImportExportUtility; 26 27/** 28 * Extension Manager Install Utility 29 * @internal This class is a specific ExtensionManager implementation and is not part of the Public TYPO3 API. 30 */ 31class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface 32{ 33 /** 34 * @var \TYPO3\CMS\Extbase\Object\ObjectManager 35 */ 36 public $objectManager; 37 38 /** 39 * @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility 40 */ 41 protected $dependencyUtility; 42 43 /** 44 * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility 45 */ 46 protected $fileHandlingUtility; 47 48 /** 49 * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility 50 */ 51 protected $listUtility; 52 53 /** 54 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository 55 */ 56 public $extensionRepository; 57 58 /** 59 * @var \TYPO3\CMS\Core\Package\PackageManager 60 */ 61 protected $packageManager; 62 63 /** 64 * @var \TYPO3\CMS\Core\Cache\CacheManager 65 */ 66 protected $cacheManager; 67 68 /** 69 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher 70 */ 71 protected $signalSlotDispatcher; 72 73 /** 74 * @var \TYPO3\CMS\Core\Registry 75 */ 76 protected $registry; 77 78 /** 79 * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager 80 */ 81 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager) 82 { 83 $this->objectManager = $objectManager; 84 } 85 86 /** 87 * @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility 88 */ 89 public function injectDependencyUtility(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility) 90 { 91 $this->dependencyUtility = $dependencyUtility; 92 } 93 94 /** 95 * @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility 96 */ 97 public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility) 98 { 99 $this->fileHandlingUtility = $fileHandlingUtility; 100 } 101 102 /** 103 * @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility 104 */ 105 public function injectListUtility(\TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility) 106 { 107 $this->listUtility = $listUtility; 108 } 109 110 /** 111 * @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository 112 */ 113 public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository) 114 { 115 $this->extensionRepository = $extensionRepository; 116 } 117 118 /** 119 * @param \TYPO3\CMS\Core\Package\PackageManager $packageManager 120 */ 121 public function injectPackageManager(\TYPO3\CMS\Core\Package\PackageManager $packageManager) 122 { 123 $this->packageManager = $packageManager; 124 } 125 126 /** 127 * @param \TYPO3\CMS\Core\Cache\CacheManager $cacheManager 128 */ 129 public function injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager) 130 { 131 $this->cacheManager = $cacheManager; 132 } 133 134 /** 135 * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher 136 */ 137 public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher) 138 { 139 $this->signalSlotDispatcher = $signalSlotDispatcher; 140 } 141 142 /** 143 * @param \TYPO3\CMS\Core\Registry $registry 144 */ 145 public function injectRegistry(\TYPO3\CMS\Core\Registry $registry) 146 { 147 $this->registry = $registry; 148 } 149 150 /** 151 * Helper function to install an extension 152 * also processes db updates and clears the cache if the extension asks for it 153 * 154 * @param array $extensionKeys 155 * @throws ExtensionManagerException 156 */ 157 public function install(...$extensionKeys) 158 { 159 $flushCaches = false; 160 foreach ($extensionKeys as $extensionKey) { 161 $this->loadExtension($extensionKey); 162 $extension = $this->enrichExtensionWithDetails($extensionKey, false); 163 $this->saveDefaultConfiguration($extensionKey); 164 if (!empty($extension['clearcacheonload']) || !empty($extension['clearCacheOnLoad'])) { 165 $flushCaches = true; 166 } 167 } 168 169 if ($flushCaches) { 170 $this->cacheManager->flushCaches(); 171 } else { 172 $this->cacheManager->flushCachesInGroup('system'); 173 } 174 $this->reloadCaches(); 175 $this->updateDatabase($extensionKeys); 176 177 foreach ($extensionKeys as $extensionKey) { 178 $this->processExtensionSetup($extensionKey); 179 $this->emitAfterExtensionInstallSignal($extensionKey); 180 } 181 } 182 183 /** 184 * @param string $extensionKey 185 */ 186 public function processExtensionSetup($extensionKey) 187 { 188 $extension = $this->enrichExtensionWithDetails($extensionKey, false); 189 $this->ensureConfiguredDirectoriesExist($extension); 190 $this->importInitialFiles($extension['siteRelPath'] ?? '', $extensionKey); 191 $this->importStaticSqlFile($extension['siteRelPath']); 192 $this->importT3DFile($extension['siteRelPath']); 193 } 194 195 /** 196 * Helper function to uninstall an extension 197 * 198 * @param string $extensionKey 199 * @throws ExtensionManagerException 200 */ 201 public function uninstall($extensionKey) 202 { 203 $dependentExtensions = $this->dependencyUtility->findInstalledExtensionsThatDependOnMe($extensionKey); 204 if (is_array($dependentExtensions) && !empty($dependentExtensions)) { 205 throw new ExtensionManagerException( 206 \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate( 207 'extensionList.uninstall.dependencyError', 208 'extensionmanager', 209 [$extensionKey, implode(',', $dependentExtensions)] 210 ), 211 1342554622 212 ); 213 } 214 $this->unloadExtension($extensionKey); 215 } 216 217 /** 218 * Wrapper function to check for loaded extensions 219 * 220 * @param string $extensionKey 221 * @return bool TRUE if extension is loaded 222 */ 223 public function isLoaded($extensionKey) 224 { 225 return $this->packageManager->isPackageActive($extensionKey); 226 } 227 228 /** 229 * Reset and reload the available extensions 230 */ 231 public function reloadAvailableExtensions() 232 { 233 $this->listUtility->reloadAvailableExtensions(); 234 } 235 236 /** 237 * Wrapper function for loading extensions 238 * 239 * @param string $extensionKey 240 */ 241 protected function loadExtension($extensionKey) 242 { 243 $this->packageManager->activatePackage($extensionKey); 244 } 245 246 /** 247 * Wrapper function for unloading extensions 248 * 249 * @param string $extensionKey 250 */ 251 protected function unloadExtension($extensionKey) 252 { 253 $this->packageManager->deactivatePackage($extensionKey); 254 $this->emitAfterExtensionUninstallSignal($extensionKey); 255 $this->cacheManager->flushCachesInGroup('system'); 256 } 257 258 /** 259 * Emits a signal after an extension has been installed 260 * 261 * @param string $extensionKey 262 */ 263 protected function emitAfterExtensionInstallSignal($extensionKey) 264 { 265 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionInstall', [$extensionKey, $this]); 266 } 267 268 /** 269 * Emits a signal after an extension has been uninstalled 270 * 271 * @param string $extensionKey 272 */ 273 protected function emitAfterExtensionUninstallSignal($extensionKey) 274 { 275 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionUninstall', [$extensionKey, $this]); 276 } 277 278 /** 279 * Checks if an extension is available in the system 280 * 281 * @param string $extensionKey 282 * @return bool 283 */ 284 public function isAvailable($extensionKey) 285 { 286 return $this->packageManager->isPackageAvailable($extensionKey); 287 } 288 289 /** 290 * Reloads the package information, if the package is already registered 291 * 292 * @param string $extensionKey 293 * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageStateException if the package isn't available 294 * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageKeyException if an invalid package key was passed 295 * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackagePathException if an invalid package path was passed 296 * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageManifestException if no extension configuration file could be found 297 */ 298 public function reloadPackageInformation($extensionKey) 299 { 300 if ($this->packageManager->isPackageAvailable($extensionKey)) { 301 $this->reloadOpcache(); 302 $this->packageManager->reloadPackageInformation($extensionKey); 303 } 304 } 305 306 /** 307 * Fetch additional information for an extension key 308 * 309 * @param string $extensionKey 310 * @param bool $loadTerInformation 311 * @internal 312 * @return array 313 * @throws ExtensionManagerException 314 */ 315 public function enrichExtensionWithDetails($extensionKey, $loadTerInformation = true) 316 { 317 $extension = $this->getExtensionArray($extensionKey); 318 if (!$loadTerInformation) { 319 $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfInformation([$extensionKey => $extension]); 320 } else { 321 $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation([$extensionKey => $extension]); 322 } 323 324 if (!isset($availableAndInstalledExtensions[$extensionKey])) { 325 throw new ExtensionManagerException( 326 'Please check your uploaded extension "' . $extensionKey . '". The configuration file "ext_emconf.php" seems to be invalid.', 327 1391432222 328 ); 329 } 330 331 return $availableAndInstalledExtensions[$extensionKey]; 332 } 333 334 /** 335 * @param string $extensionKey 336 * @return array 337 * @throws ExtensionManagerException 338 */ 339 protected function getExtensionArray($extensionKey) 340 { 341 $availableExtensions = $this->listUtility->getAvailableExtensions(); 342 if (isset($availableExtensions[$extensionKey])) { 343 return $availableExtensions[$extensionKey]; 344 } 345 throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081); 346 } 347 348 /** 349 * Creates directories as requested in ext_emconf.php 350 * 351 * @param array $extension 352 */ 353 protected function ensureConfiguredDirectoriesExist(array $extension) 354 { 355 $this->fileHandlingUtility->ensureConfiguredDirectoriesExist($extension); 356 } 357 358 /** 359 * Gets the content of the ext_tables.sql and ext_tables_static+adt.sql files 360 * Additionally adds the table definitions for the cache tables 361 * 362 * @param array $extension 363 * @deprecated since TYPO3 v9, will be removed with TYPO3v10 364 */ 365 public function processDatabaseUpdates(array $extension) 366 { 367 trigger_error('This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED); 368 $extTablesSqlFile = Environment::getPublicPath() . '/' . $extension['siteRelPath'] . 'ext_tables.sql'; 369 $extTablesSqlContent = ''; 370 if (file_exists($extTablesSqlFile)) { 371 $extTablesSqlContent .= file_get_contents($extTablesSqlFile); 372 } 373 if ($extTablesSqlContent !== '') { 374 try { 375 $this->updateDbWithExtTablesSql($extTablesSqlContent); 376 } catch (\TYPO3\CMS\Core\Database\Schema\Exception\StatementException $e) { 377 throw new ExtensionManagerException( 378 $e->getMessage(), 379 1476340371 380 ); 381 } 382 } 383 384 $this->importStaticSqlFile($extension['siteRelPath']); 385 $this->importT3DFile($extension['siteRelPath']); 386 } 387 388 /** 389 * Emits a signal to manipulate the tables definitions 390 * 391 * @param string $extensionKey 392 * @throws ExtensionManagerException 393 * @return mixed 394 * @deprecated since TYPO3 v9, will be removed with TYPO3v10 395 * @see \TYPO3\CMS\Core\Database\Schema\SqlReader::emitTablesDefinitionIsBeingBuiltSignal 396 */ 397 protected function emitTablesDefinitionIsBeingBuiltSignal($extensionKey) 398 { 399 $signalReturn = $this->signalSlotDispatcher->dispatch(__CLASS__, 'tablesDefinitionIsBeingBuilt', [[], $extensionKey]); 400 // This is important to support old associated returns 401 $signalReturn = array_values($signalReturn); 402 $sqlString = $signalReturn[0]; 403 if (!is_array($sqlString)) { 404 throw new ExtensionManagerException( 405 sprintf( 406 'The signal %s of class %s returned a value of type %s, but array was expected.', 407 'tablesDefinitionIsBeingBuilt', 408 __CLASS__, 409 gettype($sqlString) 410 ), 411 1382360258 412 ); 413 } 414 if (!empty($sqlString)) { 415 trigger_error( 416 sprintf( 417 'The signal %s of class %s is deprecated and will be removed in TYPO3 v10.0.', 418 'tablesDefinitionIsBeingBuilt', 419 __CLASS__ 420 ), 421 E_USER_DEPRECATED 422 ); 423 } 424 return $sqlString; 425 } 426 427 /** 428 * Reload Cache files and Typo3LoadedExtensions 429 */ 430 public function reloadCaches() 431 { 432 $this->reloadOpcache(); 433 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::loadExtLocalconf(false); 434 \TYPO3\CMS\Core\Core\Bootstrap::loadBaseTca(false); 435 \TYPO3\CMS\Core\Core\Bootstrap::loadExtTables(false); 436 } 437 438 /** 439 * Reloads PHP opcache 440 */ 441 protected function reloadOpcache() 442 { 443 GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive(); 444 } 445 446 /** 447 * Executes all safe database statements. 448 * Tables and fields are created and altered. Nothing gets deleted or renamed here. 449 * 450 * @param array $extensionKeys 451 */ 452 protected function updateDatabase(array $extensionKeys) 453 { 454 $sqlReader = GeneralUtility::makeInstance(SqlReader::class); 455 $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class); 456 $sqlStatements = []; 457 $sqlStatements[] = $sqlReader->getTablesDefinitionString(); 458 foreach ($extensionKeys as $extensionKey) { 459 $sqlStatements += $this->emitTablesDefinitionIsBeingBuiltSignal($extensionKey); 460 } 461 $sqlStatements = $sqlReader->getCreateTableStatementArray(implode(LF . LF, array_filter($sqlStatements))); 462 $updateStatements = $schemaMigrator->getUpdateSuggestions($sqlStatements); 463 464 $updateStatements = array_merge_recursive(...array_values($updateStatements)); 465 $selectedStatements = []; 466 foreach (['add', 'change', 'create_table', 'change_table'] as $action) { 467 if (empty($updateStatements[$action])) { 468 continue; 469 } 470 $selectedStatements = array_merge( 471 $selectedStatements, 472 array_combine(array_keys($updateStatements[$action]), array_fill(0, count($updateStatements[$action]), true)) 473 ); 474 } 475 476 $schemaMigrator->migrate($sqlStatements, $selectedStatements); 477 } 478 479 /** 480 * Save default configuration of an extension 481 * 482 * @param string $extensionKey 483 */ 484 protected function saveDefaultConfiguration($extensionKey) 485 { 486 $extensionConfiguration = $this->objectManager->get(ExtensionConfiguration::class); 487 $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfiguration($extensionKey); 488 } 489 490 /** 491 * Update database / process db updates from ext_tables 492 * 493 * @param string $rawDefinitions The raw SQL statements from ext_tables.sql 494 * @deprecated since TYPO3 v9, will be removed with TYPO3v10 495 */ 496 public function updateDbWithExtTablesSql($rawDefinitions) 497 { 498 trigger_error('This method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED); 499 $sqlReader = GeneralUtility::makeInstance(SqlReader::class); 500 $statements = $sqlReader->getCreateTableStatementArray($rawDefinitions); 501 if (count($statements) !== 0) { 502 $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class); 503 $schemaMigrationService->install($statements); 504 } 505 } 506 507 /** 508 * Import static SQL data (normally used for ext_tables_static+adt.sql) 509 * 510 * @param string $rawDefinitions 511 */ 512 public function importStaticSql($rawDefinitions) 513 { 514 $sqlReader = GeneralUtility::makeInstance(SqlReader::class); 515 $statements = $sqlReader->getStatementArray($rawDefinitions); 516 517 $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class); 518 $schemaMigrationService->importStaticData($statements, true); 519 } 520 521 /** 522 * Remove an extension (delete the directory) 523 * 524 * @param string $extension 525 * @throws ExtensionManagerException 526 */ 527 public function removeExtension($extension) 528 { 529 $absolutePath = $this->fileHandlingUtility->getAbsoluteExtensionPath($extension); 530 if ($this->fileHandlingUtility->isValidExtensionPath($absolutePath)) { 531 if ($this->packageManager->isPackageAvailable($extension)) { 532 // Package manager deletes the extension and removes the entry from PackageStates.php 533 $this->packageManager->deletePackage($extension); 534 } else { 535 // The extension is not listed in PackageStates.php, we can safely remove it 536 $this->fileHandlingUtility->removeDirectory($absolutePath); 537 } 538 } else { 539 throw new ExtensionManagerException('No valid extension path given.', 1342875724); 540 } 541 } 542 543 /** 544 * Checks if an update for an extension is available which also resolves dependencies. 545 * 546 * @internal 547 * @param Extension $extensionData 548 * @return bool 549 */ 550 public function isUpdateAvailable(Extension $extensionData) 551 { 552 return (bool)$this->getUpdateableVersion($extensionData); 553 } 554 555 /** 556 * Returns the updateable version for an extension which also resolves dependencies. 557 * 558 * @internal 559 * @param Extension $extensionData 560 * @return bool|Extension FALSE if no update available otherwise latest possible update 561 */ 562 public function getUpdateableVersion(Extension $extensionData) 563 { 564 // Only check for update for TER extensions 565 $version = $extensionData->getIntegerVersion(); 566 567 /** @var $extensionUpdates[] \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */ 568 $extensionUpdates = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion( 569 $extensionData->getExtensionKey(), 570 $version, 571 0, 572 false 573 ); 574 if ($extensionUpdates->count() > 0) { 575 foreach ($extensionUpdates as $extensionUpdate) { 576 try { 577 $this->dependencyUtility->checkDependencies($extensionUpdate); 578 if (!$this->dependencyUtility->hasDependencyErrors()) { 579 return $extensionUpdate; 580 } 581 } catch (ExtensionManagerException $e) { 582 } 583 } 584 } 585 return false; 586 } 587 588 /** 589 * Uses the export import extension to import a T3D or XML file to PID 0 590 * Execution state is saved in the this->registry, so it only happens once 591 * 592 * @param string $extensionSiteRelPath 593 */ 594 protected function importT3DFile($extensionSiteRelPath) 595 { 596 $registryKeysToCheck = [ 597 $extensionSiteRelPath . 'Initialisation/data.t3d', 598 $extensionSiteRelPath . 'Initialisation/dataImported', 599 ]; 600 foreach ($registryKeysToCheck as $registryKeyToCheck) { 601 if ($this->registry->get('extensionDataImport', $registryKeyToCheck)) { 602 // Data was imported before => early return 603 return; 604 } 605 } 606 $importFileToUse = null; 607 $possibleImportFiles = [ 608 $extensionSiteRelPath . 'Initialisation/data.t3d', 609 $extensionSiteRelPath . 'Initialisation/data.xml' 610 ]; 611 foreach ($possibleImportFiles as $possibleImportFile) { 612 if (!file_exists(Environment::getPublicPath() . '/' . $possibleImportFile)) { 613 continue; 614 } 615 $importFileToUse = $possibleImportFile; 616 } 617 if ($importFileToUse !== null) { 618 /** @var ImportExportUtility $importExportUtility */ 619 $importExportUtility = $this->objectManager->get(ImportExportUtility::class); 620 try { 621 $importResult = $importExportUtility->importT3DFile(Environment::getPublicPath() . '/' . $importFileToUse, 0); 622 $this->registry->set('extensionDataImport', $extensionSiteRelPath . 'Initialisation/dataImported', 1); 623 $this->emitAfterExtensionT3DImportSignal($importFileToUse, $importResult); 624 } catch (\ErrorException $e) { 625 $logger = $this->objectManager->get(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__); 626 $logger->log(\TYPO3\CMS\Core\Log\LogLevel::WARNING, $e->getMessage()); 627 } 628 } 629 } 630 631 /** 632 * Emits a signal after an t3d file was imported 633 * 634 * @param string $importFileToUse 635 * @param int $importResult 636 */ 637 protected function emitAfterExtensionT3DImportSignal($importFileToUse, $importResult) 638 { 639 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionT3DImport', [$importFileToUse, $importResult, $this]); 640 } 641 642 /** 643 * Imports a static tables SQL File (ext_tables_static+adt) 644 * Execution state is saved in the this->registry, so it only happens once 645 * 646 * @param string $extensionSiteRelPath 647 */ 648 protected function importStaticSqlFile($extensionSiteRelPath) 649 { 650 $extTablesStaticSqlRelFile = $extensionSiteRelPath . 'ext_tables_static+adt.sql'; 651 if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) { 652 $extTablesStaticSqlFile = Environment::getPublicPath() . '/' . $extTablesStaticSqlRelFile; 653 $shortFileHash = ''; 654 if (file_exists($extTablesStaticSqlFile)) { 655 $extTablesStaticSqlContent = file_get_contents($extTablesStaticSqlFile); 656 $shortFileHash = md5($extTablesStaticSqlContent); 657 $this->importStaticSql($extTablesStaticSqlContent); 658 } 659 $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, $shortFileHash); 660 $this->emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile); 661 } 662 } 663 664 /** 665 * Emits a signal after a static sql file was imported 666 * 667 * @param string $extTablesStaticSqlRelFile 668 */ 669 protected function emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile) 670 { 671 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionStaticSqlImport', [$extTablesStaticSqlRelFile, $this]); 672 } 673 674 /** 675 * Imports files from Initialisation/Files to fileadmin 676 * via lowlevel copy directory method 677 * 678 * @param string $extensionSiteRelPath relative path to extension dir 679 * @param string $extensionKey 680 */ 681 protected function importInitialFiles($extensionSiteRelPath, $extensionKey) 682 { 683 $importRelFolder = $extensionSiteRelPath . 'Initialisation/Files'; 684 if (!$this->registry->get('extensionDataImport', $importRelFolder)) { 685 $importFolder = Environment::getPublicPath() . '/' . $importRelFolder; 686 if (file_exists($importFolder)) { 687 $destinationRelPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . $extensionKey; 688 $destinationAbsolutePath = Environment::getPublicPath() . '/' . $destinationRelPath; 689 if (!file_exists($destinationAbsolutePath) && 690 GeneralUtility::isAllowedAbsPath($destinationAbsolutePath) 691 ) { 692 GeneralUtility::mkdir($destinationAbsolutePath); 693 } 694 GeneralUtility::copyDirectory($importRelFolder, $destinationRelPath); 695 $this->registry->set('extensionDataImport', $importRelFolder, 1); 696 $this->emitAfterExtensionFileImportSignal($destinationAbsolutePath); 697 } 698 } 699 } 700 701 /** 702 * Emits a signal after extension files were imported 703 * 704 * @param string $destinationAbsolutePath 705 */ 706 protected function emitAfterExtensionFileImportSignal($destinationAbsolutePath) 707 { 708 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionFileImport', [$destinationAbsolutePath, $this]); 709 } 710} 711