1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Extensionmanager\Controller; 17 18use TYPO3\CMS\Core\Core\Environment; 19use TYPO3\CMS\Core\Messaging\FlashMessage; 20use TYPO3\CMS\Core\Package\Exception; 21use TYPO3\CMS\Core\Package\Exception\PackageStatesFileNotWritableException; 22use TYPO3\CMS\Core\Registry; 23use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; 24use TYPO3\CMS\Core\Utility\GeneralUtility; 25use TYPO3\CMS\Core\Utility\PathUtility; 26use TYPO3\CMS\Extbase\Utility\LocalizationUtility; 27use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException; 28use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService; 29use TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility; 30use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility; 31use TYPO3\CMS\Extensionmanager\Utility\InstallUtility; 32 33/** 34 * Controller for handling extension related actions like 35 * installing, removing, downloading of data or files 36 * @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API. 37 */ 38class ActionController extends AbstractController 39{ 40 /** 41 * @var InstallUtility 42 */ 43 protected $installUtility; 44 45 /** 46 * @var FileHandlingUtility 47 */ 48 protected $fileHandlingUtility; 49 50 /** 51 * @var ExtensionModelUtility 52 */ 53 protected $extensionModelUtility; 54 55 /** 56 * @var ExtensionManagementService 57 */ 58 protected $managementService; 59 60 /** 61 * @param InstallUtility $installUtility 62 */ 63 public function injectInstallUtility(InstallUtility $installUtility) 64 { 65 $this->installUtility = $installUtility; 66 } 67 68 /** 69 * @param FileHandlingUtility $fileHandlingUtility 70 */ 71 public function injectFileHandlingUtility(FileHandlingUtility $fileHandlingUtility) 72 { 73 $this->fileHandlingUtility = $fileHandlingUtility; 74 } 75 76 /** 77 * @param ExtensionModelUtility $extensionModelUtility 78 */ 79 public function injectExtensionModelUtility(ExtensionModelUtility $extensionModelUtility) 80 { 81 $this->extensionModelUtility = $extensionModelUtility; 82 } 83 84 /** 85 * @param ExtensionManagementService $managementService 86 */ 87 public function injectManagementService(ExtensionManagementService $managementService) 88 { 89 $this->managementService = $managementService; 90 } 91 92 /** 93 * Toggle extension installation state action 94 * 95 * @param string $extensionKey 96 */ 97 protected function toggleExtensionInstallationStateAction($extensionKey) 98 { 99 $installedExtensions = ExtensionManagementUtility::getLoadedExtensionListArray(); 100 try { 101 if (in_array($extensionKey, $installedExtensions)) { 102 // uninstall 103 $this->installUtility->uninstall($extensionKey); 104 } else { 105 // install 106 $extension = $this->extensionModelUtility->mapExtensionArrayToModel( 107 $this->installUtility->enrichExtensionWithDetails($extensionKey, false) 108 ); 109 if ($this->managementService->installExtension($extension) === false) { 110 $this->redirect('unresolvedDependencies', 'List', null, ['extensionKey' => $extensionKey]); 111 } 112 } 113 } catch (ExtensionManagerException|PackageStatesFileNotWritableException $e) { 114 $this->addFlashMessage($e->getMessage(), '', FlashMessage::ERROR); 115 } 116 $this->redirect('index', 'List', null, [ 117 self::TRIGGER_RefreshModuleMenu => true, 118 self::TRIGGER_RefreshTopbar => true 119 ]); 120 } 121 122 /** 123 * Install an extension and omit dependency checking 124 * 125 * @param string $extensionKey 126 */ 127 public function installExtensionWithoutSystemDependencyCheckAction($extensionKey) 128 { 129 $this->managementService->setSkipDependencyCheck(true); 130 $this->forward('toggleExtensionInstallationState', null, null, ['extensionKey' => $extensionKey]); 131 } 132 133 /** 134 * Remove an extension (if it is still installed, uninstall it first) 135 * 136 * @param string $extension 137 * @return string 138 */ 139 protected function removeExtensionAction($extension) 140 { 141 try { 142 if (Environment::isComposerMode()) { 143 throw new ExtensionManagerException( 144 'The system is set to composer mode. You are not allowed to remove any extension.', 145 1590314046 146 ); 147 } 148 149 $this->installUtility->removeExtension($extension); 150 $this->addFlashMessage( 151 LocalizationUtility::translate( 152 'extensionList.remove.message', 153 'extensionmanager', 154 [ 155 'extension' => $extension, 156 ] 157 ) ?? '' 158 ); 159 } catch (ExtensionManagerException|Exception $e) { 160 $this->addFlashMessage($e->getMessage(), '', FlashMessage::ERROR); 161 } 162 163 return ''; 164 } 165 166 /** 167 * Download an extension as a zip file 168 * 169 * @param string $extension 170 */ 171 protected function downloadExtensionZipAction($extension) 172 { 173 $fileName = $this->fileHandlingUtility->createZipFileFromExtension($extension); 174 $this->sendZipFileToBrowserAndDelete($fileName); 175 } 176 177 /** 178 * Sends a zip file to the browser and deletes it afterwards 179 * 180 * @param string $fileName 181 */ 182 protected function sendZipFileToBrowserAndDelete(string $fileName): void 183 { 184 header('Content-Type: application/zip'); 185 header('Content-Length: ' . filesize($fileName)); 186 header('Content-Disposition: attachment; filename="' . PathUtility::basename($fileName) . '"'); 187 readfile($fileName); 188 unlink($fileName); 189 die; 190 } 191 192 /** 193 * Reloads the static SQL data of an extension 194 * 195 * @param string $extension 196 */ 197 protected function reloadExtensionDataAction($extension) 198 { 199 $extension = $this->installUtility->enrichExtensionWithDetails($extension, false); 200 $registryKey = $extension['siteRelPath'] . 'ext_tables_static+adt.sql'; 201 202 $registry = GeneralUtility::makeInstance(Registry::class); 203 $registry->remove('extensionDataImport', $registryKey); 204 205 $this->installUtility->processExtensionSetup($extension['key']); 206 207 $this->redirect('index', 'List'); 208 } 209} 210