Files
gutachten_t3/typo3/sysext/install/Classes/Updates/AbstractDownloadExtensionUpdate.php
T
2026-10-19 08:18:39 +02:00

184 lines
6.4 KiB
PHP

<?php
namespace TYPO3\CMS\Install\Updates;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility;
use TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility;
use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
use TYPO3\CMS\Extensionmanager\Utility\ListUtility;
/**
* Download extension from TER
*/
abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface, ConfirmableInterface, ChattyInterface
{
/**
* @var string
*/
protected $repositoryUrl = 'https://typo3.org/fileadmin/ter/@filename';
/**
* @var OutputInterface
*/
protected $output;
/**
* @var \TYPO3\CMS\Install\Updates\ExtensionModel
*/
protected $extension;
/**
* @param OutputInterface $output
*/
public function setOutput(OutputInterface $output): void
{
$this->output = $output;
}
/**
* Execute the update
* Called when a wizard reports that an update is necessary
*
* @return bool
*/
public function executeUpdate(): bool
{
return $this->installExtension($this->extension);
}
/**
* This method can be called to install an extension following all proper processes
* (e.g. installing in extList, respecting priority, etc.)
*
* @param \TYPO3\CMS\Install\Updates\ExtensionModel $extension
* @return bool whether the installation worked or not
* @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
*/
protected function installExtension(ExtensionModel $extension): bool
{
$updateSuccessful = true;
/** @var ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
/** @var ListUtility $extensionListUtility */
$extensionListUtility = $objectManager->get(ListUtility::class);
$availableExtensions = $extensionListUtility->getAvailableExtensions();
$extensionKey = $extension->getKey();
$isExtensionAvailable = !empty($availableExtensions[$extensionKey]);
$isComposerMode = Environment::isComposerMode();
if (!$isComposerMode && !$isExtensionAvailable) {
/** @var TerUtility $extensionTerUtility */
$extensionTerUtility = $objectManager->get(TerUtility::class);
$t3xContent = $this->fetchExtension($extensionKey, $extension->getVersionString());
if (empty($t3xContent)) {
$updateSuccessful = false;
$this->output->writeln('<error>The extension ' . $extensionKey . ' could not be downloaded.</error>');
}
$t3xExtracted = $extensionTerUtility->decodeExchangeData($t3xContent);
if (empty($t3xExtracted) || !is_array($t3xExtracted) || empty($t3xExtracted['extKey'])) {
$updateSuccessful = false;
$this->output->writeln('<error>The extension ' . $extensionKey . ' could not be extracted.</error>');
}
/** @var FileHandlingUtility $extensionFileHandlingUtility */
$extensionFileHandlingUtility = $objectManager->get(FileHandlingUtility::class);
$extensionFileHandlingUtility->unpackExtensionFromExtensionDataArray($t3xExtracted);
// The listUtility now needs to have the regenerated list of packages
$extensionListUtility->reloadAvailableExtensions();
}
if ($isComposerMode && !$isExtensionAvailable) {
$updateSuccessful = false;
$this->output->writeln(
'<warning>The extension ' . $extensionKey
. ' can not be downloaded since Composer is used for package management. Please require this '
. 'extension as package via Composer: "composer require ' . $extension->getComposerName()
. ':^' . $extension->getVersionString() . '"</warning>'
);
}
if ($updateSuccessful) {
/** @var InstallUtility $extensionInstallUtility */
$extensionInstallUtility = $objectManager->get(InstallUtility::class);
$extensionInstallUtility->install($extensionKey);
}
return $updateSuccessful;
}
/**
* Fetch extension from repository
*
* @param string $extensionKey The extension key to fetch
* @param string $version The version to fetch
* @throws \InvalidArgumentException
* @return string T3X file content
*/
protected function fetchExtension($extensionKey, $version): string
{
if (empty($extensionKey) || empty($version)) {
throw new \InvalidArgumentException(
'No extension key for fetching an extension was given.',
1344687432
);
}
$filename = $extensionKey[0] . '/' . $extensionKey[1] . '/' . $extensionKey . '_' . $version . '.t3x';
$url = str_replace('@filename', $filename, $this->repositoryUrl);
return $this->fetchUrl($url);
}
/**
* Open an URL and return the response
* This wrapper method is required to try several download methods if
* the configuration is not valid or initially written by the installer.
*
* @param string $url The URL to file
* @throws \Exception
* @throws \InvalidArgumentException
* @return string File content
*/
protected function fetchUrl($url): string
{
if (empty($url)) {
throw new \InvalidArgumentException(
'No URL for downloading an extension given.',
1344687436
);
}
$fileContent = GeneralUtility::getUrl($url);
// Can not fetch url, throw an exception
if ($fileContent === false) {
throw new \RuntimeException(
'Can not fetch URL "' . $url . '". Possible reasons are network problems or misconfiguration.',
1344685036
);
}
return $fileContent;
}
}