0e2cb2db0a9d8276d32c2adc041bf83b89efb9f0
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Updates / AbstractDownloadExtensionUpdate.php
1 <?php
2 namespace TYPO3\CMS\Install\Updates;
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
17 use TYPO3\CMS\Core\Core\Environment;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Extbase\Object\ObjectManager;
20 use TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility;
21 use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility;
22 use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
23 use TYPO3\CMS\Extensionmanager\Utility\ListUtility;
24
25 /**
26 * Download extension from TER
27 */
28 abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
29 {
30 /**
31 * @var string
32 */
33 protected $title = 'Install an Extension from the Extension Repository';
34
35 /**
36 * See subclasses for more information
37 * @var array
38 */
39 protected $extensionDetails = [];
40
41 /**
42 * @var string
43 */
44 protected $repositoryUrl = 'https://typo3.org/fileadmin/ter/@filename';
45
46 /**
47 * This method can be called to install an extension following all proper processes
48 * (e.g. installing in extList, respecting priority, etc.)
49 *
50 * @param string $extensionKey
51 * @param string $customMessage
52 * @return bool whether the installation worked or not
53 */
54 protected function installExtension($extensionKey, &$customMessage)
55 {
56 $updateSuccessful = true;
57 /** @var ObjectManager $objectManager */
58 $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
59
60 /** @var ListUtility $extensionListUtility */
61 $extensionListUtility = $objectManager->get(ListUtility::class);
62 $availableExtensions = $extensionListUtility->getAvailableExtensions();
63 $extensionDetails = $this->getExtensionDetails($extensionKey);
64
65 $isExtensionAvailable = !empty($availableExtensions[$extensionKey]);
66 $isComposerMode = Environment::isComposerMode();
67
68 if (!$isComposerMode && !$isExtensionAvailable) {
69 /** @var TerUtility $extensionTerUtility */
70 $extensionTerUtility = $objectManager->get(TerUtility::class);
71 if (empty($extensionDetails)) {
72 $updateSuccessful = false;
73 $customMessage .= 'No version information for extension ' . $extensionKey . ' found. Can not install the extension.';
74 }
75 $t3xContent = $this->fetchExtension($extensionKey, $extensionDetails['versionString']);
76 if (empty($t3xContent)) {
77 $updateSuccessful = false;
78 $customMessage .= 'The extension ' . $extensionKey . ' could not be downloaded.';
79 }
80 $t3xExtracted = $extensionTerUtility->decodeExchangeData($t3xContent);
81 if (empty($t3xExtracted) || !is_array($t3xExtracted) || empty($t3xExtracted['extKey'])) {
82 $updateSuccessful = false;
83 $customMessage .= 'The extension ' . $extensionKey . ' could not be extracted.';
84 }
85
86 /** @var FileHandlingUtility $extensionFileHandlingUtility */
87 $extensionFileHandlingUtility = $objectManager->get(FileHandlingUtility::class);
88 $extensionFileHandlingUtility->unpackExtensionFromExtensionDataArray($t3xExtracted);
89
90 // The listUtility now needs to have the regenerated list of packages
91 $extensionListUtility->reloadAvailableExtensions();
92 }
93
94 if ($isComposerMode && !$isExtensionAvailable) {
95 $updateSuccessful = false;
96 $customMessage .= 'The extension ' . $extensionKey . ' can not be downloaded since ' .
97 'Composer is used for package management. Please require this ' .
98 'extension as package via Composer: ' .
99 '"composer require ' . $extensionDetails['composerName'] . ':^' . $extensionDetails['versionString'] . '"';
100 }
101
102 if ($updateSuccessful) {
103 /** @var InstallUtility $extensionInstallUtility */
104 $extensionInstallUtility = $objectManager->get(InstallUtility::class);
105 $extensionInstallUtility->install($extensionKey);
106 }
107
108 return $updateSuccessful;
109 }
110
111 /**
112 * Returns the details of a local or external extension
113 *
114 * @param string $extensionKey Key of the extension to check
115 *
116 * @return array Extension details
117 */
118 protected function getExtensionDetails($extensionKey)
119 {
120 if (array_key_exists($extensionKey, $this->extensionDetails)) {
121 return $this->extensionDetails[$extensionKey];
122 }
123
124 return [];
125 }
126
127 /**
128 * Fetch extension from repository
129 *
130 * @param string $extensionKey The extension key to fetch
131 * @param string $version The version to fetch
132 *
133 * @throws \InvalidArgumentException
134 * @return string T3X file content
135 */
136 protected function fetchExtension($extensionKey, $version)
137 {
138 if (empty($extensionKey) || empty($version)) {
139 throw new \InvalidArgumentException(
140 'No extension key for fetching an extension was given.',
141 1344687432
142 );
143 }
144
145 $filename = $extensionKey[0] . '/' . $extensionKey[1] . '/' . $extensionKey . '_' . $version . '.t3x';
146 $url = str_replace('@filename', $filename, $this->repositoryUrl);
147
148 return $this->fetchUrl($url);
149 }
150
151 /**
152 * Open an URL and return the response
153 *
154 * This wrapper method is required to try several download methods if
155 * the configuration is not valid or initially written by the installer.
156 *
157 * @param string $url The URL to file
158 *
159 * @throws \Exception
160 * @throws \InvalidArgumentException
161 * @return string File content
162 */
163 protected function fetchUrl($url)
164 {
165 if (empty($url)) {
166 throw new \InvalidArgumentException(
167 'No URL for downloading an extension given.',
168 1344687436
169 );
170 }
171
172 $fileContent = GeneralUtility::getUrl($url);
173
174 // Can not fetch url, throw an exception
175 if ($fileContent === false) {
176 throw new \RuntimeException(
177 'Can not fetch URL "' . $url . '". Possible reasons are network problems or misconfiguration.',
178 1344685036
179 );
180 }
181
182 return $fileContent;
183 }
184 }